Java内存区域
详细的描述在下面的文章中都说过,不在赘述
《Java内存区域划分》
这里重点说一下方法区在Java不同版本中的位置以及堆内存的划分。
堆内存划分为新生代、老年代
堆划分
(Java8之前,Java8已经没有了永生代)这里有个坑要说一下,很多人以为永生代也在堆内,这是错误的,为啥嘞,说的简单点,堆为啥要分代,是为了GC(收集垃圾),那你说神仙都长生不老了,你还想让他死,你这不是不讲理,当然神仙也是要计划生育滴,下面在详细讲
第二个坑:认为方法区就是永生代,这也是错误滴,只是用永生代来实现方法区,那我要是用新生代实现,还叫新生代了?
好了,我们来看新生代,有三块区域,Eden(伊甸园)、From Survivor(诺亚方舟一号)、To Survivor(诺亚方舟二号),为啥这么叫呢?他们的比例是8:1:1
- Eden:
在jvm实现中,大多数情况下,对象优先在Eden分配,上帝当年造的人都是在这里出生的,还有一小部分情况,比如JIT技术,是不在堆上分配的,就像我猴哥,石头缝里蹦出来的。 - Survivor:我们知道,Java 中的大部分对象通常不需长久存活,具有朝生夕灭的性质。这时候新生代会进行Minor GC,Minor GC用的是复制算法中, 如果对象在Eden出生并经过第一次Minor GC后仍然存活, 并且能被Survivor容纳的话, 将被移动到Survivor空间中, 并且对象年龄设为1 对象在Survivor区中每“熬过” 一次Minor GC, 年龄就增加1岁, 当它的年龄增加到一定程度(默认为15岁) ,就将会被晋升到老年代中。
这就是我为啥叫他诺亚方舟,你逃过一劫,你就可以进来,渡劫多了,哎,就升仙了,那为啥需要俩呢,总有渡劫失败的,我要把活着的赶到另一艘船上,才能一个不拉的收尸是吧 - 老年代 :
大对象直接进入老年代(-XX: PretenureSizeThreshold);
经历过15次Minor GC还活着的对象进入老年代;
大对象我们就认为他天生神体吧,这个货在船上放不下,一不小心船就坏了(避免在Eden和survivor之间发生大量的复制),所以就送去天堂吧,那么没有一个好爹的就只能渡劫了,总有一天会成仙的 - 动态对象年龄判定:为了能更好地适应不同程序的内存状况, 虚拟机并不是永远地要求对象的年龄必须达到了MaxTenuringThreshold才能晋升老年代, 如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半, 年龄大于或等于该年龄的对象就可以直接进入老年代, 无须等到MaxTenuringThreshold中要求的年龄。
- 空间分配担保:在发生Minor GC之前, 虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间, 如果这个条件成立, 那么Minor GC可以确保是安全的。 如果不成立, 则虚拟机会查HandlePromotionFailure设置值是否允许担保失败。 如果允许, 那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于, 将尝试着进行一次Minor GC, 尽管这次Minor GC是有风险的; 如果小于, 或者HandlePromotionFailure设置不允许冒险, 那这时也要改为进行一次Full GC,如果某次Minor GC存活后的对象突增, 远远高于平均值的话, 依然会导致担保失败(Handle Promotion Failure) 。
为什么需要担保?
新生代使用复制收集算法, 但为了内存利用率, 只使用
其中一个Survivor空间来作为轮换备份, 因此当出现大量对象在Minor GC后仍然存活的情况(最极端的情况就是内存回收后新生代中所有对象都存活) , 就需要老年代进行分配担保, 把Survivor无法容纳的对象直接进入老年代。
好不容易渡劫完了,要是换船的时候没位置了找谁哭去,所以渡劫前,要看看剩下的仙位是不是够以前平均升仙成功的人,或者某次渡劫成功的人特别多,那就只有清理仙位了,要是万一船上没位置了,那恭喜你,升仙了
写了一半发布了,突然想起来忘了写方法区了:
在java7之前,jvm把GC分代收集扩展至方法区,(方法区是用永生代实现的),这样垃圾收集器可以像管理Java堆一样管理这部分内存, 能够省去专门为方法区编写内存管理代码的工作。这块内存也称为非堆
在Java7中,开始移除永生代,符号表被移动到 Native Heap中,字符串常量池和类的静态变量被移动到 Heap中,Java8中,完全移除了永生代,改用元空间代替(Metaspace),元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。
给出官方的说法:JEP 122:Move part of the contents of the permanent generation in Hotspot to the Java heap and the remainder to native memory.(移除了永久代(PermGen),替换为元空间(Metaspace);永久代中的 class metadata 转移到了 native memory(本地内存,而不是虚拟机);永久代中的 interned Strings 和 class static variables 转移到了 Java heap;)
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.
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.
(元空间分成多个块,每个块与一个类加载器相关联,每个块存储多个类(该加载器加载的类)的元数据,当类加载器GG时,会释放相关的块空间)
Alternatives(为啥这么做呢,是为了融合Hotspot和JRockit)
网友评论