Java垃圾回收机制

   对象被判定为垃圾的标准:没有被其他对象引用

判定对象是否为垃圾的算法

引用计数算法(非主流)
判断对象的引用数量
  1. 判断对象的引用数量来决定对象是否可以被回收;
  2. 每个对象实例都有一个引用计数器,被引用则+1,完成引用则-1;(完成指值改变或生命周期过期);
  3. 任何引用计数为0的对象实例可以被当做垃圾收集;
    **优点:**执行效率高,程序执行受影响较小;
    **缺点:**无法检测出循环引用的情况,导致内存泄漏;(eg:父对象有一个对子对象的引用,子对象引用父对象)
    在这里插入图片描述
可达性分析算法(主流算法)

通过判断对象的引用链是否可达来决定对象是否可以被回收(基于离散数学的图论)
在这里插入图片描述

可作为GC root的对象
  1. 虚拟机栈中引用的对象(栈堆中的本地变量表);
  2. 方法区中的常量引用的对象;
  3. 方法区中的类静态属性引用的对象;
  4. 本地方法栈中JNI(Native方法)的引用对象;
  5. 活跃线程的引用对象

垃圾回收算法

标记-清除算法(Mark and Sweep)

    标记:从根集合开始扫描,对存活的对象进行标记;
   清除:对堆内存从头到尾进行线性遍历,回收不可达对象内存;
在这里插入图片描述
   缺点:会产生大量不连续的碎片(碎片化)。

复制算法(Coping)
  1. 分为对象面和空闲面;
  2. 对象在对象面上创建;
  3. 存活的对象从对象面复制到空闲面;
  4. 将对象面所有对象内存清除;

在这里插入图片描述

优点:
  1. 解决了碎片化问题;
  2. 顺序分配内存,简单高效;
  3. 适用于对象存活率低的场景;
缺点

所需内存较大,适合新生代。

标记-整理算法(Compacting)
  1. 标记:从根集合进行扫描,对存活的对象进行标记;
  2. 清除:移动所有存活的对象,且按照内存地址次序排列,然后将末端内存地址以后的内存全部回收。

在这里插入图片描述

优点
  1. 避免内存的不连续行;
  2. 不用设置两块内存互换;
  3. 适用于存活率高的场景;
缺点

数据移动增加了CPU成本,适合老年代

分代收集算法(Generational Collector)
  1. 垃圾回收算法的组合拳;
  2. 按照对象生命周期的不同划分区域以采用不同的垃圾回收算法;
  3. 目的:提高JVM的回收效率。
GC分类
  1. Minor GC
  2. Full GC

词汇普及

新生代:主要是用来存放新生的对象。

   Eden区:Java新对象的出生地(如果新创建的对象占用内存很大,则直接分配到老年代)。当Eden区内存不够的时候就会触发MinorGC,对新生代区进行一次垃圾回收。

   ServivorTo:保留了一次MinorGC过程中的幸存者。

   ServivorFrom:上一次GC的幸存者,作为这一次GC的被扫描者。

   MinorGC的过程:MinorGC采用复制算法。首先,把Eden和ServivorFrom区域中存活的对象复制到ServicorTo区域(如果有对象的年龄以及达到了老年的标准,则赋值到老年代区),同时把这些对象的年龄+1(如果ServicorTo不够位置了就放到老年区);然后,清空Eden和ServicorFrom中的对象;最后,ServicorTo和ServicorFrom互换,原ServicorTo成为下一次GC时的ServicorFrom区。

   -XX:MaxTenuringThreshold 可设置新生代到老年代的年龄,默认15。

对象如何晋升到老年代
  1. 经历一定Minor次数依然存活的对象;
  2. Survivor存活不下的对象;
  3. 新生成的大对象(-XX:+PretenuerSizeThreshold)
常用的调优参数
  1. -XX:SurvivorRatio: Eden和Survivor的比值,默认是8(也就是8:1)
  2. -XX:NewRatio: 老年代和新生代内存大小的比例,默认为2(也就是2:1)
  3. -XX:MaxTenuringThreshold: 对象从新生代晋升到老年代经过GC次数的最大阈值(默认15,也就是所说的年龄)

在这里插入图片描述
在这里插入图片描述

老年代:主要存放应用程序中生命周期长的内存对象。

标记-清理算法或标记-整理算法

老年代的GC回收
  1. Full GC 和Major GC
  2. Full GC 比Minor GC慢,但执行频率低

   Full GC是指对老年代和新生代都进行垃圾回收,Major GC有些解读中 == Full GC。
   MajorGC采用标记—清除算法:首先扫描一次所有老年代,标记出存活的对象,然后回收没有标记的对象。MajorGC的耗时比较长,因为要扫描再回收。MajorGC会产生内存碎片,为了减少内存损耗,我们一般需要进行合并或者标记出来方便下次直接分配。 当老年代也满了装不下的时候,就会抛出OOM(Out of Memory)异常。

触发Full GC的条件
  1. 老年代空间不足;(不要创建太大的对象)
  2. 永久代空间不足;(JDK6、7以前才有)
  3. CMS GC时出现promotion failed,concurrent mode failure
  4. Minor GC晋升到老年代的平均大小大于老年代的剩余空间(晋升过程时先检查晋升内容大小与老年代剩余内存大小)
  5. 调用System.gc() (只是提醒虚拟机,而不是绝对进行回收)
  6. 使用RMI进行RPC或管理的JDK应用,每小时执行1次Full GC
Major GC
永久代:

   指内存的永久保存区域,主要存放Class和Meta(元数据)的信息,Class在被加载的时候被放入永久区域. 它和和存放实例的区域不同,GC不会在主程序运行期对永久区域进行清理。所以这也导致了永久代的区域会随着加载的Class的增多而胀满,最终抛出OOM异常。 在Java8中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。

JDK6,JDK7
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值