JVM垃圾收集器

    科技2022-08-21  113

    文章目录

    1、什么是Stop the World?2、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?3、说一下JVM有哪些垃圾回收器?

    1、什么是Stop the World?

    简称STW,即在执行垃圾收集算法时,Java应用程序的其他所有除了垃圾收集收集器线程之外的线程都被挂起,此时程序只能运行GC线程进行运行,其他线程则会全部暂停,等待GC线程执行完毕后才能再次运行。这些工作都是由虚拟机在后台自动发起和自动完成的,是在用户不可见的情况下把用户正常工的线程全部停下来,这对于很多的尤其是实时性要求很高的程序来说是难以接受的。但是有些时候这个是无法避免的,随着垃圾收集器的改进,用户线程的停顿时间也在不断缩短。

    所以垃圾回收坚持的一个原则就是尽量减少“Stop The World”的时间和次数。

    多半是由于GC引起的: 1、老年代空间不足 2、System.gc()方法调用 3、新生代GC时老年代的内存平均值大于老年代剩余空间 4、又连续的大对象需要分配 5、Dump线程,分析存在阻塞和瓶颈的线程 6、死锁检查

    2、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?

    对于GC来说,当程序员创建对象时,GC就开始监控和这个对象的地址、大小以及使用情况。 通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象,通过这种方式确定哪些对象时可达的,哪些对象是不可达的,当GC确定一些对象为不可达时,GC就有责任回收这些内存空间。 程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。

    3、说一下JVM有哪些垃圾回收器?

    串行(Serial):使用单线程进行垃圾回收的回收器。 并行(Parallel):之多条垃圾收集西城并行工作,但此时用户线成任然处于等待状态。 并发(Concurrnet):只用户线成与垃圾收集线成同时执行(不一定是并行,可以是交替执行),用户线成在继续执行,而垃圾收集器运行在另一个CPU上。

    回收新生代的收集器:Serial、ParNew、Parallel Scavenge。回收老年代的收集器包括Serial Old、Parallel Old、CMS。回收整个Java堆的G1收集器。

    (1)Serial收集器(复制算法):新生代单线程收集器,标记和清理都是单线程,有点事简单高效。 (2)ParNew收集器(复制算法):新生代并行收集器,实际上是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现。 (3)Parallel Scavenge收集器(复制算法):新生代并行收集器,追求高吞吐量,高效开勇CPU,吞吐量=用户线程时间/(用户线程时间+GC线程时间),高吞吐量可以高效率的利用CPU时间,尽快完成程序的运算任务,适合后台应用等对用户交互相应要求不高的场合。 (4)Serial Old收集器(标记- 整理算法):老年代单线程收集器,Serial收集器的老年代版本。 (5)Parallel Old收集器(标记-整理算法):老年代并行收集器,吞吐量优先,Parallel Scavenge收集器的老年代版本; (6)CMS收集器(标记-清除算法):老年代并行收集器,以获取最短回收停顿时间为目标的收集器,具有高并发、低停顿的特点,追求跟高GC回收停顿时间。

    CMS并不是独占的回收器,也就是说,CMS回收的过程中应用程序任然在不停的工作,又会有新的来及不断产生,所以在使用CMS的过程应该确保应用程序的内存足够可用,CMS不会等到应用程序饱和的时候才回去回收垃圾,而是在某一阀值(默认为68)的时候开始回收,也就是说当老年代的空间使用率达到68%的时候会执行CMS。如果内存使用率增长很快,在CMS执行过程中,已经出现了内存不足的情况,此时,CMS回收就会失败,虚拟机将启动老年代 Serial 进行垃圾回收,这会导致应用程序中断,直到垃圾回收完成后才会正常工作,这个过程GC的停顿时间可能较长,所以阀值的设置要根据实际情况设置。

    初始标记:暂停所有的其他线程,并记录下直接与root相连的对象并发标记: 同时开启GC和用户线程,用一个闭包结构去记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。因为用户线程可能会不断的更新引用域,GC线程无法保证可达性分析的实时性。所以这个算法里会跟踪记录这些发生引用更新的地方。重新标记:重新标记阶段就是为了修正并标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间段。 并发清除:开启用户线成,同时GC线成开始对未标记的区域做清扫。

    优点:并发收集、低停顿 缺点:

    无法处理浮动垃圾,使用的标记-清除算法会导致收集结束产生大量空间碎片。对CPU资源非常敏感,虽然在并发阶段不会导致用户线成停顿,但是会因为占用了一部分想爱你成而导致应用程序变慢,总吞吐量下降,CMS默认启动的回收线程数是(cpu数量+3)/4。

    (7)G1收集器(标记-整理算法):Java堆并行收集器,G1收集器是JDK1.7提供的一个新收集器,G1收集器基于标记-整理算法实现,也就是说不会产生内存碎片。此外,G1收集器不同于之前收集器的一个重要特点是:G1回收的范围是整个Java堆(包括新生代、老年代),而前六种收集器的范围仅限于新生代或老年代。

    特点

    1、并行与并发

    G1能充分利用CPU、多核环境下的硬件优势,使用多个CPU来缩短stop-the-world停顿时间,部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让java程序继续执行。

    2、分代收集

    虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但还是保留了分代的概念。

    能独立管理整个GC堆(老年代和新生代),而不需要与其他收集器搭配。能够采用不同方式处理不同时期的对象。虽然保留分代概念,但Java堆的内存布局有很大差别。将整个堆划分为多个大小相等的独立区域(Region)。新生代和老年代不再是物理隔离,它们都是一部分Region(不需要连续)的集合。

    3、空间整合

    与CMS的“标记-清理”算法不同,G1从整体上来看是基于“标记整理”算法实现的收集器,从局部上来看是基于复制算法实现的。

    从整体看,是基于标记-整理算法从局部(两个Region间)看,是基于复制算法;

    4、可预测的停顿

    这是G1相对于CMS的另一个大优势,降低停顿时间是G1和CMS共同关注的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型。可以明确指定M毫秒时间片内,垃圾收集消耗的时间不超过N毫秒。在低停顿的同时实现高吞吐量。

    G1它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,而都是一部分Region(不需要连续)的集合。

    建立可预测的时间模型

    G1收集器之所以能建立可预测的停顿时间模型,是因为它可以有计划地避免在整个Java堆进行全区域的垃圾收集。G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region(这也就是Garbage-First名称的由来)。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限的时间内可以获取尽可能高的收集效率。

    避免全表扫描—Remebered Set

    G1把Java堆分为多个Region,就是“化整为零”。但是Region不可能是孤立的,一个对象分配在某个Region中,可以与整个Java堆任意的对象发生引用关系。在做可达性分析确定对象是否存活的时候,需要扫描整个Java堆才能保证准确性,这显然是对GC效率的极大伤害。

    为了避免全堆扫描的发生,虚拟机为G1中每个Region维护了一个与之对应的Remembered Set。虚拟机发现程序在对Reference类型的数据进行写操作时,会产生一个Write Barrier暂时中断写操作。

    检查Reference引用的对象是否处于不同的Region之中(在分代的例子中就是检查是否老年代中的对象引用了新生代中的对象),如果是,便通过CardTable把相关引用信息记录到被引用对象所属的Region的Remembered Set之中。当进行内存回收时,在GC根节点的枚举范围中加入Remembered Set即可保证不对全堆扫描也不会有遗漏。

    如果不计算维护Remembered Set的操作,G1收集器的运作大致可划分为以下几个步骤:

    初始标记(Initial Marking) 仅仅只是标记一下GC Roots 能直接关联到的对象,并且修改TAMS(Nest Top Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可以的Region中创建对象,此阶段需要停顿线程,但耗时很短。

    并发标记(Concurrent Marking) 从GC Root 开始对堆中对象进行可达性分析,找到存活对象,此阶段耗时较长,但可与用户程序并发执行。

    最终标记(Final Marking) 为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程的Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中,这阶段需要停顿线程,但是可并行执行。

    筛选回收(Live Data Counting and Evacuation) 首先对各个Region中的回收价值和成本进行排序,根据用户所期望的GC 停顿是时间来制定回收计划。此阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。

    Processed: 0.027, SQL: 9