课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
昆明IT培训的老师知道,方法区的作用是存储Java类的结构信息,当我们创建对象实例后,对象的类型信息存储在方法区之中,实例数据存放在堆中;实例数据指的是在Java中创建的各种实例对象以及它们的值,类型信息指的是定义在Java代码中的常量、静态变量、以及在类中声明的各种方法、方法字段等等;同时可能包括即时编译器编译后产生的代码数据。通过在运行时产生大量的类,或者工程本身具有大量的类,而方法区分配的空间不足以容纳如此多的类信息的时候就会产生方法区内存溢出异常。
运行时常量池是方法取得一部分,程序中使用到的String类型字面量以及基本数据类型的一部分数据会存储在常量池中。我们使用String.intern()方法来测试,是运行时常量池发生内存溢出。此方法的作用是:如果字符串常量池中不包含一个等于此String对象的字符串,则将此对象包含的字符串添加到常量池中,并返回此对象的引用。
使方法区发生内存溢出的要旨:
程序运行时动态创建的大量类,导致方法区内存空间不足
程序中存有大量字面量等数据导致常量区内存不足
据说此段代码在jdk6之前的版本中运行时会产生:Exception in thread "main" java.lang.OutOfMemoryError: PermGen space其中PermGen space指示内存溢出发生在运行时常量池中。
但是,我在jdk7的环境中运行得到的结果却是:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 指示内存溢出发生在堆中而不是方法区中的常量池!!!都说实践是检验真理的唯一标准,果真是没错的。因为在JDK1.2 ~ JDK6的实现中,HotSpot使用永久代实现方法区,而从JDK7开始Oracle HotSpot开始移除永久代,JDK7中符号表被移动到Native Heap中,字符串常量和类引用被移动到Java Heap中。在JDK8中,永久代已完全被元空间(Meatspace)所取代。关于常量池的存放位置还有待进一步研究,不过上段代码是可以引起常量池的内存溢出的。
通过运行时动态产生大量的类产生方法区内存溢出示例这里就不提供了,书中提供了使用CGLib使方法区出现内存异常。
只要知道发生内存溢出时显示:PermGen space那就是方法区内存溢出准没错啦。