JVM--方法区(Method Area)

方法区

供各线程共享的运行时内存区域。它存储了每一个类的结构信息,例如运行时常量池(Runtime Constant Pool)、字段和方法数据、构造函数和普通方法的字节码内容。

上面说的是规范,在不同虚拟机里实现是不一样的,最典型的就是永久代(PermGen)和元空间(Metaspace)

实例变量存在堆内存中,和方法区无关。

在实际的 JVM 实现中,它不一定是由单一的特殊区域所实现,不同的实现可以放在不同的地方:

永久代(Permanent Generation)

永久代是 HotSpot 虚拟机在 JDK7 及以前对方法区的具体实现,而永久代也在 heap 中(但注意,其它虚拟机并没有永久代,这是 HotSpot 虚拟机特有的)。

在 JDK1.7 中,移除永久代的工作就已经开始了,原先存储在永久代的部分数据转移到了Java heap 或者 native memory,但永久代仍存在于 JDK1.7 中,并没完全移除。移除工作主要包括下面三点:

  • 符号引用(Symbolic Reference)转移到了native memory
  • Interned Strings转移到了heap
  • 静态变量从instanceKlass对象(PermGen内)末尾转移到了java.lang.Class对象(heap内)的末尾

元空间(metaspace)

从 JDK 8 开始的 HotSpot 虚拟机完全移除了 PermGen,改为在 native memory 里存放这些元数据。新的用于存放元数据的内存空间叫做 Metaspace。

取消永久代主要有以下几点原因:

  • 字符串存在永久代中,容易出现性能问题和内存溢出
  • 永久代会为 GC 带来不必要的复杂度,并且回收效率偏低
  • 便于将 HotSpot 与 JRockit 合二为一(JRockit 中并没有永久代)

在 Java 8 中抛出堆溢出的示例:

public class StringHeapError {
    public static void main(String[] args) {
        String temp = "world";
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            String str = temp + temp;
            temp = str;
            str.intern();
        }
    }
}

输出:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

如果是在 JDK 6 中,这会提示 PermGen Space 溢出

下面是抛出 Metaspace 溢出的例子,用了 Cglib 生成大量的代理类。不过在这之前需要修改JVM启动参数,设置为:

-XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M
public class ClassInfo {
    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                    return proxy.invokeSuper(obj, args);
                }
            });
            enhancer.create();
        }
    }

    static class OOMObject { }
}

输出:

Exception in thread "main" java.lang.OutOfMemoryError: Metaspace

可以看到,类信息(classes metadata)放到了 Metaspace 中,而 Interned Strings、静态变量放到了 heap 上。

发布了665 篇原创文章 · 获赞 1894 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/cold___play/article/details/104075794
今日推荐