jvm堆分代

JVM堆结构图及分代

JVM虚拟机: JVM内存分代策略

Java虚拟机根据对象存活的周期不同,把堆内存划分为几块,一般分为新生代、老年代和永久带,永久带也叫持久带

(对HotSpot虚拟机而言),这就是JVM的内存分代的策略.

现在我们看到的java堆,实际划分的颗粒度会更细,实际上把堆按分代的结构来处理呢,那就引申出一个问题了,

为什么要分代,对内存是虚拟机管理的内存中的最大的一块,也是垃圾回收最频繁的一块区域,我们程序所有的

对象实例都存放在堆内存中. 给堆内存分代是为了提高对象内存分配和来及回收的效率,你想如果堆是一块

内存,然后在这个堆内存中存所有的对象,而且有些都不一样,有些是朝生夕死的,有些是永久存活的,有些是

中间环节的,你把这些对象全都塞到一个内存里,对于垃圾回收来讲,是不是难度大大提升,第二个问题,由于

内存存放对象的时候是连续的,以后未来你要挑不同的对象做回收,对内存空间做释放,也就是你内存当中会

产生大量的碎片,产生碎片又会带来什么影响呢,产生碎片最直接的影响就会内存造成浪费,比如原来这一块

是200K,200K,200K三块,存了三个对象,然后中间的对象呗回收了,被回收这个对象被释放了200K,现在我要

存一个对象300K存不进去,这个时候只能往后面找有没有连续的两个200K,那这个200K就浪费掉了,除非

小于200K的对象能new上,否则空间就被闲置了所以这就是产生碎片的原因,如果不分代对于垃圾回收来讲就

很复杂.


分而治之,分代最核心的一个策略,试想一下,如果对内存没有区域划分,所有新创建的对象和声明周期很长的

对象放在一起,随着程序的执行,对内存需要频繁的进行垃圾收集,而每次回收都要遍历所有的对象,遍历这些

对象所花费的时间代价是巨大的,会严重影响GC的效率,也是就是难度的一部分,这简直太可怕了.

有了内存分代,情况就不同了,新创建的对象会在新生代中生成,经过多次回收仍然存活下来的对象放在老年代中

静态属性、类信息等放在永久代中,新生代存活的时间短,只需要在新生代频繁进行GC,老年代中对象生命周期

长,内存回收频率相对较低,永久代由于是最长的了,JMV一般不会对永久代做垃圾回收,虽然说它可以,但是它

一般不会这么去做.


还可以根据不同年代的特点采用合适的垃圾回收算法,分代收集大大提高了收集效率,这些都是内存分代所带来

的好处,它把原来一大块的东西,分成了小块,然后把不同的对象放在不同的块中,经过重重过滤,新生代里面有

一个eden区,这里放的永远都是刚出生的对象,如果eden区的对象并没有被回收,或者在一定的时间内没有被

回收,这个对象的声明周期很长,那么就不能放在eden区了,要放到老年代里,然后再是持久代,新生代和持久代

仿佛就是一个漏斗在层层过滤,能够跑到过滤最终点的,一定是这个对象声明周期最长的,才会到持久代,

所以他采用这样一个方式来解决问题,这是一个很好的方式.


内存分代划分:

Java虚拟机将堆内存划分为新生代,老年代,持久代,永久带是HotSpot虚拟机所特有的概念,如果你采用的是

JDK1.4之前的,不是这个核心的,那就没有永久代这么一说,它采用永久代的方式来实现方法区,其它的虚拟机

实现没有这一概念,而且HotSpot也有取消永久代的趋势,在JDK1.7 HotSpot已经开始去永久代,把原本放在

永久代的字符串常量池移出,永久代主要存放常量,类信息,静态变量数据,你有没有发现堆里面的永久代存放

的东西和方法区存放的东西相似,都是生命周期比较长的,可以把这些内容放到方法区里面去存储,可以节省一块

内存空间

这个图是颗粒度非常细的java堆的演示,仅是堆的进一步细化的演示,其实我们的堆可以分成5块区域,

JVM会把它分成5块区域, Eden,from,to这三块被称之为年轻代,old老年代,permanent被称为持久代

也有把old和permanent这两块放在一起的,在年轻代里又分成三块,from,to这两块的叫法有好多,统称为

Survivor幸存者,对于from有的人叫做survivor0,有的叫s0,有的叫s1,为什么要用0,因为程序查数是从0

开始的,也有叫from,to的,这三块共同构成了年轻代,前面的eden伊甸园,为什么要用这个来命名呢,说明所有

对象的出生都是在这个区域里的,他是婴儿的摇篮,大部分对象的初始化都是在这里,有的对象运行完了就没事了,

在这个横向划分当中,Eden的垃圾回收频率是最高的,而且在Eden区里基本能够回收到整个对象的百分之80以上,

甚至百分之85的对象,都会在Eden里运行完就回收掉了,唯独剩余的一部分怎么办呢,他也不会放在Eden里,它会

放到Survivor Space,再进一步决定是不是要回收,如果他又没有被回收掉,然后再把它放在old区.


我们在讲来垃圾回收器的时候,由于不同的区域回收的频率不一样,那么所采用的收集器也是不一样的,收集器

不仅仅是对堆这一块做回收,它会细化到什么程度呢,对堆里不同的区域做回收,那么也就是说在这个区域里边,

从Survivor之后一分为二,左边的一个垃圾回收器,右边的一个垃圾回收器,即便是你不指定,JVM也是这么做的,

他不是一个垃圾回收器,而是对不同的堆用不同的垃圾回收器,根据你的区域,根据你的分代,这个叫分代垃圾收集,

是不是Eden有一个垃圾回收,是不是from有一个垃圾回收,不是这样的,它的垃圾回收颗粒度没有这么细,因为

它觉得没有必要,他就是从中间带和老年代作为一个中间轴,来采用两代的垃圾回收


新生代(Young Generation):

新生成的对象优先存放在新生代中,新生代对象朝生夕死,存活率很低,在新生代中,常规应用一次垃圾收集,

一般可以回收70% ~ 90% 的空间,回收率很高.

HotSpot将新生代分为三代,一块较大的Eden空间和两块较小的Survivor空间,默认比例是8:1:1,8是80%是

Eden,剩下的10%,10%是Survivor区,为什么要给Eden区放这么大的空间,而给Survivor放这么小呢, 因为你想

啊,因为大部分的空间都被回收掉了,剩下的就一小部分了,分那么大的空间会造成很大的浪费,没必要,所以

java虚拟机所划分的区域是8:1:1, HotSpot采用复制算法来回收新生代,什么叫复制算法,设置这个比例是

为了充分利用内存空间,减少浪费,新生成的对象在Eden区分配,大对象除外,大对象直接进入老年代,Eden区

会放大部分的对象,并不是全部的,另一部分就是大对象,当Eden区没有足够空间进行分配时,虚拟机将会

发起一次Minor GC, 它的收集器分为两种, 一种是次收集器,一种是全收集器,其实又叫Minor GC的,Minor GC

就是去收集Eden里的一些收集器,就是指收集年轻代的收集器, GC开始时,对象只会存在于Eden区和From 

Survivor区,to Survivor 区, GC进行时, Eden区中所有存活的对象都会被复制到 to Survivor区, 而在

from Survivor区中, 仍存活的对象会根据他们的年龄值决定去向, 年龄值达到年龄阀值(默认是15次),就是

被回收15次还没有被回收掉,新生代中的对象每熬过一轮垃圾回收,当年龄增加1的时候,如果年龄值达到15了,

放心不会被回收了,而是放在老年代当中了, 没有达到阀值的对象会被复制到to Survivor区. 接着清空

Eden区和From Survivor区,新生代中存活的对象都在to Survivor区. 接着from Survivor和to Survivor

区会交换它们的角色,其实这就是我们要讲的复制算法的事件. 其实很好理解,如果年龄没有超过15次,还在

这里放着,内存空间肯定是连续的,通过Minor GC次回收器的回收,超过15次的肯定不会被回收,那怎么办呢,

他不能就把它放在这里呢,放在这里第一个还是会产生碎片,复制算法非常好理解,他会把这些没有被回收的对象

直接拷贝到to Survivor区,并且按照连续的来存储,然后把from区全都清空,这个时候既保证了空间的释放,

也保证了空间的连续,这就是复制算法,to Survivor里的也不是永久存放,也是通过一个阀值,如果也是比如

15次垃圾回收后存活,那就放在old区老年代,然后再把to Survivor区清空,老年代old区是为了给survivor区

做一个担保,就像我们去银行贷款一样,old区老年代其实就是给新生代做一个担保,总之,不管怎样都会保证

to Survivor区在一轮GC后都是空的, GC时当to Survivor区没有足够的空间存放上一次新生代收集下来的

存活对象时,需要老年代进行分配担保,将这些对象存放在老年代中.

新生代就是用来折腾这戏对象,谁能进入到老年代里.


老年代(old generation):在新生代中经历了多次,具体要看虚拟机配置的阀值,GC后仍然存活下来的对象会

进入老年代中. 老年代中的对象生命周期较长,存活率较高,在老年代中进行GC的频率相对而言较低,而且回收

的速度也比较慢.

老年代的垃圾回收机制,肯定不会像新生代那么频繁,因为老年代生命周期较长,还频繁收集,第一是无用,第二

降低虚拟机的性能,没有必要做高频的垃圾回收.


永久代(Permanent Generation):永久代存储类信息,常量,静态变量,即时编译器编译后的代码等数据,

对这一区域而言,Java虚拟机规范指出可以不进行垃圾收集,一般而言不会进行垃圾回收.


JDK1.8和1.9里已经没有永久代了,最多就是到老年代了.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值