提示:参考深入理解Java虚拟机
前言
运行时常量池是方法区的一部分,Java虚拟机规范中描述是堆的逻辑部分,一般垃圾回收在这个区域只是针对常量池的,这个区域1.7以前叫永久代,为了配合垃圾收集,后来发现不好用,1.7开始去永久代。1.8划分成元空间。这个区域主要存储已经被虚拟机加载的类型信息,常量,静态变量等
一、常量池实战
因为我用的环境是1.8,由于JDK7以后方法区移到了元空间,字符串常量池放到了Java堆中,所以-XX:MaxPermSize参数或者-XX:MaxMeta-spaceSize都不会出现OOM,因为字符串常量池在堆中,我配置的堆空间
-Xmx6M
代码
/**
* @author jc
*/
public class ObjectVMTest {
static class OOMobject{}
public static void main(String[] args) {
//这里用这个list是为了避免垃圾回收,这个list现在是在GCRoot集里面,这是垃圾回收的一个引用追踪算法
List<OOMobject> list = new ArrayList<>();
while (true) {
list.add(new OOMobject());
}
}
}
结果
二、方法区
参数设置
-XX:MaxMetaspaceSize=10M
代码
/**
* @author jc
*/
public class VMMethod {
public static void main(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(o, args);
}
});
enhancer.create();
}
}
static class OOMOBJECT {
}
}
结果
总结
常量池还有一个经典面试题
String s2 = "qw";
String s1 = new String("qw");
System.out.println(s1.equals(s2));
}
结果为true
new一个字符串的时候,会把这个字符串字面量去常量池中查找,如果有就直接返回这个字面量的引用