JVM---分代管理

我们常说的gc,就是垃圾会收集机制,他负责是讲系统中的无用对象回收,但是具体的回收算法是什么嘞?下面我写下我的见解。

在java虚拟机中,我们会把java内存分成 新生代 和 老年代,还有方法区。 对应的存储心 new 出的对象,通过n次gc后的对象和基本不会执行垃圾回收的方法区。(当然,说老年代是通过n次gc后进去的对象,这样的逻辑是不严谨的)


1、新生代

新生代分成了三块,分别是eden,翻译过来就是伊甸园,很形象的翻译,说明所有的新生对象多是在这个地方的,其他俩个一个存放gc后的幸存者,一个是临时存放幸存者的地方。
这三块区域的比值是8:1:1。他们的gc算法是被称作 复制–清理 的算法。复制-清理算法的大致过程是:新生的对象被放到eden区,但是eden区域是有限的啊,所以,当eden区内存满的时候,触发gc过程。(当然,这发生新生代的gc之前,老年代还需要进行一些处理)
GC触发后,虚拟机首先把eden区和幸存区的有效对象都复制到临时的幸存区,然后,GC对着除了临时幸存区之外的新生代区域做全部GC,这样会把所有的对象的都清理完成,然后,在把临时幸存区的对象移动到幸存区。
那么,一次这样的新生代GC就完成了。

2、老年代

老年代的内存大小和新生代的大小,大致是相同的,而老年代的对象也是从新生代或者是直接放进去的。
那么,新生代的对象怎么晋级到老年代呢?三种途径:

  1. 对象中在新生代中,会有一个属性,记录他经历的GC次数,如果经历了15次,那么,就会直接进入老年代。
  2. 并不是所有的对象都会经历15的GC才会进入老年代,当同一个GC年龄的对象所占的内存大小已经大雨了幸存区的50%了,会进制老年代。
  3. 也不是所有的新生对象都会直接进入新生代,而是看这个对象的大小,如果,该对象太大,新生代的eden区域不足以放置,那么会有老年代的内存进行分担。

    对于老年代,JVM一般有2中方法来进行内存的回收,一种是标记–清理,另一种是标记–整理。来着的区别是啥呢,标记–清理是把对象直接清理掉了,那么这样的结果就是,引用不可达的对象清理,但是内存不连续。但是标记–整理会把引用可达的对象放到一边,引用不可达的对象放到另一次,这样清理后的内存空间就是连续的了。在垃圾回回收器中,cms垃圾回收期用到的就是标记–清理;而G1垃圾回收器用的则是标记–整理。
    那么,什么时候进行老年代的牢记回收呢?当然,当老年代的对象内存满了之后,必然要进行垃圾回收,但是,我们还有一种情况,这个我们在前边提到过,就是在新生代进行GC之前,我们要检测老年代的属性。
    大致过程是这样的:当进行新生代的GC时,首先去取老年代看看,当老年代的可用空间大于新生代对象的空间总和的时候,新生代可以进行GC,为啥?因为,即使新生代的GC过后,所有的对象都是可达的,都是有效的,那么他们都要进入老年代,这样,老年代放不下,势必造成对象丢失。
    如果老年代的可用空间比新生代的所有对象空间综合小的话,那么会看老年代是否进行内存分担,进行分担的话,还要看老年代所能使用的空间和新生代晋升上的对象大小的平均值比较,如果老年代大,可以冒险进行新生代GC,但是如果老年代小,那么,老年代就要进行Full gc,进行垃圾回收了。而冒险的话,有可能,新生代垃圾回收晋级过来的对象太大,那么这是,老年代也要进行full gc。
    (我们说的【新生代晋升上的对象大小的平均值】的意思是:每次gc晋级的综合除以晋级次数,就是晋级对象的平均值)

    3、方法区

    JVM对方法去的回收效率太低了,方法区也被称为不死区,所以,基本不会进行回收,及时回收,用的算法也是标记–清理。


对象可达

这里涉及到一个问题:怎么知道对象可达?一般是俩中算法:

  1. 引用计数。很好理解,一个对象,有一个引用,对象的这个属性就 + 1,当为0的时候,为不可达。
  2. 对象可达。这种是用图的概念来表示的,没有一个引用指向该对象就为不可达。

    类对象的可达

    类对象怎么判断不可达:
    1、 类对象被卸载了。
    2、类实例被回收了。
    3、类.class没有别的地方引用了。

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lovergo/article/details/79973648
个人分类: 杂类 随笔
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭