[公告] String.intern()常量池溢出
rxin2009
2013-11-19
最近碰到个问题,请各位不吝赐教:
在做socket服务器的时候,每发一个消息都会产生一个uuid,然后调用这个uuid的intern()方法,如果长期执行的应该会OOM,但是测试的结果不是我想的那样,以下是测试代码 /** * @param args */ public static void main(String[] args) { long sum = 0; try { while (true) { sum++; UUIDUtils.createId().intern(); } } finally { System.out.println(sum); } } 以下是参数设置 -Xss1M -Xms5M -Xmx5M -XX:PermSize=5m -XX:MaxPermSize=5m 我这里的测试结果是这样的,程序单独跑不会OOM,但开启jvisualvm后到一定时间会OOM? |
|
RednaxelaFX
2013-11-19
开VisualVM会OOM具体是什么原因我没仔细看,但楼主给的程序例子正常跑不会OOM的原因很明显:HotSpot VM的interned String可以被GC。
HotSpot VM内部有一个哈希表叫做StringTable,它用于记录所有interned String的引用。而从StringTable出发的引用会被视为与弱引用相似的特殊引用,如果某个String对象除了被StringTable引用外没有别的活引用,它就可以被GC清理掉。 楼主的例子正是这种情况。生成了UUID之后并没有持续持有对它的活引用,而是intern()完就不管了。楼主可以打开-XX:+PrintGCDetails看GC日志是不是大部分都是full GC(由PermGen满而触发的GC)。 另外楼主是用什么版本的JDK来测的?JDK7的HotSpot VM的interned String不是放在PermGen的喔。 |
|
ol_beta
2013-11-19
RednaxelaFX 写道 开VisualVM会OOM具体是什么原因我没仔细看,但楼主给的程序例子正常跑不会OOM的原因很明显:HotSpot VM的interned String可以被GC。
HotSpot VM内部有一个哈希表叫做StringTable,它用于记录所有interned String的引用。而从StringTable出发的引用会被视为与弱引用相似的特殊引用,如果某个String对象除了被StringTable引用外没有别的活引用,它就可以被GC清理掉。 楼主的例子正是这种情况。生成了UUID之后并没有持续持有对它的活引用,而是intern()完就不管了。楼主可以打开-XX:+PrintGCDetails看GC日志是不是大部分都是full GC(由PermGen满而触发的GC)。 另外楼主是用什么版本的JDK来测的?JDK7的HotSpot VM的interned String不是放在PermGen的喔。 不是说jdk8没有PermGen了吗? |
|
RednaxelaFX
2013-11-19
ol_beta 写道 不是说jdk8没有PermGen了吗?
对的,PermGen移到GC堆外变成了Metaspace。所以要问楼主是用啥版本嘛。 楼主都指定了PermSize和MaxPermSize而没说看到警告,说明肯定不是在用JDK8 |
|
rxin2009
2013-11-19
RednaxelaFX 写道 开VisualVM会OOM具体是什么原因我没仔细看,但楼主给的程序例子正常跑不会OOM的原因很明显:HotSpot VM的interned String可以被GC。
HotSpot VM内部有一个哈希表叫做StringTable,它用于记录所有interned String的引用。而从StringTable出发的引用会被视为与弱引用相似的特殊引用,如果某个String对象除了被StringTable引用外没有别的活引用,它就可以被GC清理掉。 楼主的例子正是这种情况。生成了UUID之后并没有持续持有对它的活引用,而是intern()完就不管了。楼主可以打开-XX:+PrintGCDetails看GC日志是不是大部分都是full GC(由PermGen满而触发的GC)。 另外楼主是用什么版本的JDK来测的?JDK7的HotSpot VM的interned String不是放在PermGen的喔。 环境:jdk6, 64位的win7 开visualvm发生oom很明显的,特别是字符串放大些,如 /** * @param args */ public static void main(String[] args) { long sum = 0; byte[] bytes=new byte[1024*5]; try { while (true) { sum++; new String(bytes).intern(); } } finally { System.out.println(sum); } } |
|
fh63045
2013-11-20
socket中产生的string类型数据是存放在堆中的吧!
|
|
RednaxelaFX
2013-11-20
fh63045 写道 socket中产生的string类型数据是存放在堆中的吧!
所有String实例都在Java堆中。 |
|
rxin2009
2013-11-21
RednaxelaFX 写道 fh63045 写道 socket中产生的string类型数据是存放在堆中的吧!
所有String实例都在Java堆中。 不知道什么原因,在上述环境下,开visualvm会permspace,难道你们的机子跑不会这样吗? |