(转载)谈谈JVM的垃圾回收算法及JVM参数

本文介绍了Java垃圾回收的基本概念,如如何判断对象是否为垃圾,主要的垃圾回收算法,包括标记清除、标记压缩、复制算法和分代收集算法,并详细阐述了每种算法的优缺点。此外,还提到了CMS和G1垃圾回收器,以及相关JVM配置参数。同时,文章讨论了Stop-the-World现象及其在不同回收器中的表现。

https://zhuanlan.zhihu.com/p/61662625
建议阅读原文
1,如何判断一个对象是垃圾

在谈JVM的垃圾回收算法之前,我们再来回顾下两个关键问题:

1,什么是垃圾回收?

2,如何判断一个对象是垃圾?

所谓的垃圾回收,是指回收哪些死亡的对象所占据的堆空间。

而如何判断一个对象已经死亡,有两种方式,引用计数法和可达性分析算法;

引用计数法,需要额外的空间来存储计数器,如果有一个引用指向某一个对象,则该对象的引用计数器+1,如果该引用指向另一个对象,则原先的对象计算器-1.

但这种算法,会存在循环引用的bug问题,存在内存溢出的风险。

可达性分析算法,是以GC Root作为起点,能够引用到的对象则是有用对象,反之则是死亡的。

那么,什么是GC Root,一般可以理解为堆外指向堆内的引用,包括以下常见的两种:

1,java方法栈帧中的局部变量

2,已被加载的类静态变量

下面,我们开始来谈垃圾回收算法!

1,标记清除算法

是现在垃圾算法的思想基础,它将垃圾回收分为两个阶段:

标记阶段和清除阶段。

首先,是通过根节点GC Root,标记所有从根节点开始的可达对象。

因此,未被标记的对象都是垃圾对象。

然后,在清除节点,则删除所有未被标记的对象。

标记清除算法的缺点:

1,效率不高

2,该算法会产生不连续的内存碎片,当我们需要分配较大对象时,会因为无法找到足够的连续内存空间,而不得不再次提前触发垃圾回收,如果内存还是不够,则报内存不足异常。

2,标记压缩算法

标记压缩算法是老年代的一种回收算法

首先,标记阶段跟“标记清除算法”一致

区别在于清理阶段,为了避免内存碎片产生,所有的存活对象会被压缩到内存的一端

这个算法解决之前标记清除算法的碎片问题

但是标记和压缩的效率依然不高

3,复制算法

复制算法是为了解决效率问题,它将内存一分为二,每次只使用其中一块,

这样,当这一块内容用完了,就将存活的对象复制到另一个块上,然后将另一块内存一次清理掉,这样回收的效率也就提升了,也不存在内存碎片的问题。

算法优点是回收效率高,不存在内存碎片,但是浪费内存一半的内存空间,另外在对象存活率高的情况下,采用复制算法,效率将会变低。

4,分代收集算法

目前,主流的虚拟机大都采用分代收集算法,它根据对象存活周期的不同,而将内存划分为多块区域。一般就是我们耳熟能详的新生代和老年代,然后再各自采用不同的回收算法。

新生代(Eden),对象的存活率低,所以采用复制算法

老年代(Old),对象的存活率高,所以采用标记清除或标记整理算法

对象会优先分配到新生代,如果长时间存活或者对象过大会直接分配到老年代(新生代空间不够)。

算法细节:

1,对象新建,将存放在新生代的Eden区域,注意Suvivor区又分为两块区域,FromSuv和ToSuv

2,当年轻代Eden满时,将会触发Minor GC,如果对象仍然存活,对象将会被移动到Fromsuvivor空间,对象还是在新生代

3,再次发生minor GC,对象还存活,那么将会采用复制算法,将对象移动到ToSuv区域,此时对象的年龄+1

4,再次发生minor GC,对象仍然存活,此时Survivor中跟对象Object同龄的对象还没有达到Surivivor区的一半,所以还是会继续采用复制算法,将fromSuv和ToSuv的区域进行互换

5,当多次发生monorGC后,对象Object仍然存活,且此时,此时Survivor中跟对象Object同龄的对象达到Surivivor区的一半,那么对象Object将会移动到老年代区域,或者对象经过多次的回收,年龄达到了15岁,那么也会迁移到老年代。

5,JVM配置的相关参数

-Xms2g:初始化推大小为 2g;-Xmx4g:堆最大内存为 4g;-XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4;-XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2;

6,垃圾回收器有哪些?

做垃圾回收的时候,都有一个统一的特点,叫stop the world.

往回收效率越来越高的方向来走的,垃圾回收的时间(stop the world)在变短

1,单线程回收器

采用单个线程的方式来进行回收,效率一般。服务器是多核CPU,资源无法得到更好利用

2,多线程回收器

可以充分利用CPU资源

3,CMS回收器

3.1 初始化标记

GCRoot

public class Gc{
private static SomeObject = new SomeObject();
}

class SomeObject{

}

这个时候会stop the world,但是由于我们只是标记GCRoot,所以花费的时间很短

3.2 并发标记

一边可以继续往下跟踪,做可达性分析,相比比较耗时 100

一边可以让程序继续运行,可能重新创建对象,也可能创造垃圾 20

3.3 重新标记

处理在并发标记过程中,再次产生新的垃圾,stop the world 20

3.4 并发回收

一边针对我们刚才的垃圾对象进行回收

一边程序继续运行

4,G1垃圾回收器

将内存划分多个块 ,每个块再独立进行回收

Java垃圾回收机制是Java虚拟机(JVM)自动管理内存的一种机制。在Java程序中,程序员不需要手动分配和释放内存,而是由JVM负责自动回收不再使用的对象。 Java垃圾回收机制的基本原理是通过“可达性分析”来确定哪些对象是存活的,然后回收那些不再被引用的对象。可达性分析是从一组称为“GC Roots”的起始对象开始,通过引用链来遍历和标记可达对象。无法通过引用链访问到的对象则被标记为可回收垃圾对象。 Java垃圾回收机制的工作过程分为三个阶段:标记、清除和整理。在标记阶段,垃圾回收器标记所有可达对象。在清除阶段,垃圾回收回收标记为垃圾的对象,并且释放它们所占用的内存空间。在整理阶段,垃圾回收器将存活的对象向一端移动,以便在内存布局中形成连续的内存块。这样可以解决内存碎片问题,提高内存利用率。 Java垃圾回收机制具有以下优点: 1. 自动化管理:程序员不需要手动释放内存,减少了内存泄漏和悬挂对象(对象已被释放但仍然被引用)的可能性。 2. 高效性能:Java垃圾回收机制采用分代回收算法,根据对象的存活时间将内存分为多个代,根据不同的代使用不同的垃圾回收算法,提高了回收效率。 3. 防止空指针异常:垃圾回收器可以检测并处理不再使用的对象,避免了程序运行过程中的空指针异常错误。 4. 提高开发效率:不需要手动管理内存,减少了程序员的工作量,提高了开发效率。 然而,Java垃圾回收机制也存在一些问题,比如垃圾回收过程可能会导致程序的暂停时间变长,对实时性要求较高的程序可能会受到影响。此外,垃圾回收机制的性能也会受到堆内存的大小和程序的运行负载等因素的影响。 总的来说,Java垃圾回收机制是一种非常成熟和高效的内存管理机制,它解放了程序员手动管理内存的负担,提高了开发效率和程序的健壮性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值