方法区和运行时常量池溢出:
前面提到JDK1.7还是逐步“去永久代”的事情,在此就以测试代码观察一下这件事对程序的实际影响。
String.intern()是一个Native方法,它的作用是:如果字符串常量池中已经包含了一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。在JDK1.6及之前的版本中由于常量池分配在永久代内,我们可以通过-XX:PermSize和-XX:MaxPermSize限制方法区大小,从而间接限制其中常量池的容量。

 

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。
public class RuntimeConstantPoolOOM {
/**
* -XX:PermSize=10M -XX:MaxPermSize=10M
* @param args
*/
public static void main(String[] args) {
List<String> list = new ArrayList<>();
int i = 0;
while (true){
list.add(String.valueOf(i++).intern());
}
}
}

深入理解jvm jdk1,7(13) 随笔 第1张

-XX:PermSize=10M      方法区初始化大小
-XX:MaxPermSize=10M   方法区最大上限

运行结果:
JDK1.7 一切正常,并不会抛异常。 程序一直产生字符串常量,方法区大小为10M,程序正常 说明常量池不在方法区
JDK1.6:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
 at java.lang.String.intern(Native Method)
 at test.main(test.java:13)

java.lang.OutOfMemoryError之后跟着 PermGen space,说明运行时常量池属于方法区(HotSpot虚拟机中的永久代)
 
public class RuntimeConstantPoolOOM {
/**
* -XX:PermSize=10M -XX:MaxPermSize=10M
* @param args
*/
public static void main(String[] args) {

String s = new StringBuilder("计算机").append("软件").toString();
System.out.println(s.intern() == s);

String s1 = new StringBuilder("ja").append("va").toString();
System.out.println(s1.intern() == s1);
}
}
运行结果:
JDK1.6: false false
JDK1.7: true  false


JDK1.6中,intern()方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中这个字符串实例的引用,而由StringBuilder创建的字符串实例在Java堆上,所以必然不是同一个引用,返回false。

JDK1.7中,intern()实现不会再复制实例,只是在常量池中记录首次出现的实例引用,因此intern()返回的引用和由StringBuilder创建的那个字符串实例是同一个。s.intern() == s 返回true。

s1返回false是因为“java”这个字符串在执行StringBuilder.toString()之前已经出现过,字符串常量池中已经有它的引用了,不符合“首次出现”的原则,而“计算机软件”这个字符串则是首次出现的,s1.inertn() == s1 返回false

 

"java" 字符串在StringBuilder.toString 之前出现的位置:https://blog.csdn.net/u014333083/article/details/80354900

 

 
public class JavaMethodAreaOOM {

/**
* -XX:PermSize=10M -XX:MaxPermSize=10M
* @param args
*/
public static void main(final String[] args) {
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(objects,args);
}
});

enhancer.create();
}
}

static class OOMObject {

}
}

深入理解jvm jdk1,7(13) 随笔 第2张



扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄