[公告] 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,难道你们的机子跑不会这样吗?
Global site tag (gtag.js) - Google Analytics