JAVA 方法区与堆--java7前,java7,java8各不相同

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq876551724/article/details/78845366

三种情况:
java7之前,方法区位于永久代(PermGen),永久代和堆相互隔离,永久代的大小在启动JVM时可以设置一个固定值,不可变;
java7中,存储在永久代的部分数据就已经转移到Java Heap或者Native memory。但永久代仍存在于JDK 1.7中,并没有完全移除,譬如符号引用(Symbols)转移到了native memory;字符串常量池(interned strings)转移到了Java heap;类的静态变量(class statics)转移到了Java heap。
java8中,取消永久代,方法存放于元空间(Metaspace),元空间仍然与堆不相连,但与堆共享物理内存,逻辑上可认为在堆中
Native memory:本地内存,也称为C-Heap,是供JVM自身进程使用的。当Java Heap空间不足时会触发GC,但Native memory空间不够却不会触发GC。
知乎上:R大神解答:
Oracle JDK7 / OpenJDK 7的HotSpot VM是把Symbol的存储从PermGen移动到了native memory,并且把静态变量从instanceKlass末尾(位于PermGen内)移动到了java.lang.Class对象的末尾(位于普通Java heap内)。
“常量池”如果说的是SymbolTable / StringTable,这俩table自身原本就一直在native memory里,是它们所引用的东西在哪里更有意思。上面说了,7是把SymbolTable引用的Symbol移动到了native memory,而StringTable引用的java.lang.String实例则从PermGen移动到了普通Java heap。
传送门:jdk8之后永久代去哪了?
因和这篇文章说的相同(R说的SymbolTable 即为符号引用,StringTable即字符串常量),故认为此理解正确,即 java7中,存储在永久代的部分数据就已经转移到Java Heap或者Native memory。但永久代仍存在于JDK 1.7中,并没有完全移除。譬如符号引用(Symbols)转移到了native memory;字符串常量池(interned strings)转移到了Java heap;类的静态变量(class statics)转移到了Java heap。

为什么移除永久代?
1、字符串存在永久代中,容易出现性能问题和内存溢出。
2、永久代大小不容易确定,PermSize指定太小容易造成永久代OOM
3、永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
4、Oracle 可能会将HotSpot 与 JRockit 合二为一。

在JDK1.7中, 已经把原本放在永久代的字符串常量池移出, 放在堆中. 为什么这样做呢?
因为使用永久代来实现方法区不是个好主意, 很容易遇到内存溢出的问题. 我们通常使用PermSize和MaxPermSize设置永久代的大小, 这个大小就决定了永久代的上限, 但是我们不是总是知道应该设置为多大的, 如果使用默认值容易遇到OOM错误。

类的元数据, 字符串池, 类的静态变量将会从永久代移除, 放入Java heap或者native memory。其中建议JVM的实现中将类的元数据放入 native memory, 将字符串池和类的静态变量放入java堆中. 这样可以加载多少类的元数据就不在由MaxPermSize控制, 而由系统的实际可用空间来控制.

为什么这么做呢? 减少OOM只是表因, 更深层的原因还是要合并HotSpot和JRockit的代码, JRockit从来没有一个叫永久代的东西, 但是运行良好, 也不需要开发运维人员设置这么一个永久代的大小。当然不用担心运行性能问题了, 在覆盖到的测试中, 程序启动和运行速度降低不超过1%, 但是这一点性能损失换来了更大的安全保障。

OpenJDK文档:

Success Metrics
Class metadata, interned Strings and class static variables will be moved from the permanent generation to either the Java heap or native memory.
(类元数据、内部字符串和类静态变量将从永久生成转移到Java堆或本机内存。)
The code for the permanent generation in the Hotspot JVM will be removed.
(JVM中永久代的代码将被删除。)
Application startup and footprint will not regress more than 1% as measured by a yet-to-be-chosen set of benchmarks.

Description
Move part of the contents of the permanent generation in Hotspot to the Java heap and the remainder to native memory.
(将Hotspot中永久代的部分内容移到Java堆中,其余部分移到本地内存中。)
Hotspot’s representation of Java classes (referred to here as class meta-data) is currently stored in a portion of the Java heap referred to as the permanent generation. In addition, interned Strings and class static variables are stored in the permanent generation. The permanent generation is managed by Hotspot and must have enough room for all the class meta-data, interned Strings and class statics used by the Java application. Class metadata and statics are allocated in the permanent generation when a class is loaded and are garbage collected from the permanent generation when the class is unloaded. Interned Strings are also garbage collected when the permanent generation is GC’ed.

The proposed implementation will allocate class meta-data in native memory and move interned Strings and class statics to the Java heap. Hotspot will explicitly allocate and free the native memory for the class meta-data. Allocation of new class meta-data would be limited by the amount of available native memory rather than fixed by the value of -XX:MaxPermSize, whether the default or specified on the command line.
(这个被提议的实现将在本地内存中分配类元数据,并将内部的字符串和类静态转移到Java堆中。Hotspot会显式的为类元数据分配和释放本地内存。新类元数据的分配将受可用本地内存的数量限制,而不是由-XX:MaxPermSize的值来固定,无论在命令行上是默认还是指定。)

Allocation of native memory for class meta-data will be done in blocks of a size large enough to fit multiple pieces of class meta-data. Each block will be associated with a class loader and all class meta-data loaded by that class loader will be allocated by Hotspot from the block for that class loader. Additional blocks will be allocated for a class loader as needed. The block sizes will vary depending on the behavior of the application. The sizes will be chosen so as to limit internal and external fragmentation. Freeing the space for the class meta-data would be done when the class loader dies by freeing all the blocks associated with the class loader. Class meta-data will not be moved during the life of the class.

参考:
Java8内存模型—永久代(PermGen)和元空间(Metaspace)
JAVA 方法区是在堆里面吗
Java8移除永久代
jdk8之后永久代去哪了?
Java8内存模型
OpenJDK文档

猜你喜欢

转载自blog.csdn.net/qq876551724/article/details/78845366