前段时间我们学习jvm的基础结构和gc相关的基础知识,今天我们详细讲讲几大gc。
串行 GC 对年轻代使用 mark-copy (标记-复制) 算法,对老年代使用 mark-sweep-compact (标记-清除-整理) 算法。
两者都是单线程的垃圾收集器,不能进行并行处理,所以都会触发全线暂停(STW),停止所有的应用线程因此这种 GC 算法不能充分利用多核 CPU。不管有多少 CPU 内核,JVM 在垃圾收集时都只能使用单个核心。CPU 利用率高,暂停时间长。简单粗暴,就像老式的电脑,动不动就卡死。该选项只适合几百 MB 堆内存的 JVM,而且是单核 CPU 时比较有用。想想 why?
-XX:+USeParNewGC 改进版本的 Serial GC,可以配合 CMS 使用
串行垃圾收集器(Serial Collector)是最基本、历史最悠久的垃圾收集器,它在垃圾收集的过程中会暂停其他所有的工作线程,也就是人们常说的 "Stop-The-World"。串行收集器在进行垃圾收集时只使用一个CPU或一个收集线程完成,它不仅会导致用户当前正在运行的线程停止,还不会效率地利用多核处理器的优势。
在JVM启动时,通过以下参数可以开启串行垃圾收集器:
串行垃圾收集器是一款STW(Stop The World)的收集器,当它在运行时,用户线程会被全部挂起,在完成垃圾收集之前不能恢复运行。
串行垃圾收集器的优点是简单高效(与其他收集器的单线程相比),缺点是在进行垃圾收集时需要暂停所有应用线程,因此不适用于对响应时间有较高要求的应用。
尽管串行GC停止所有的应用线程,且只有一个线程参与垃圾收集,但在以下几个场景中,串行GC仍然是一个不错的选择:
要启用串行GC,可以使用JVM参数-XX:+UseSerialGC。
假设内存大小为4GB,并以此为基础,以下是一个基于4GB堆内存的串行垃圾收集器(Serial GC)的例子,涉及年轻代和老年代的内存分布:
年轻代内存分布:
老年代内存分布:
当Eden空间和To区的内存占用达到一定阈值时,会触发Minor GC,清理Eden空间和From区的无用对象,并将存活的对象复制到To区。当老年代的内存使用率达到一定阈值或需要进行Full GC时,会触发Major GC,清理整个堆空间的垃圾。
年轻代和老年代的垃圾回收都会触发 STW 事件在年轻代使用 标记-复制 (mark-copy) 算法,在老年代使用 标记-清除-整理mark-sweepcompact) 算法。
XX:ParallelGCThreads=N 来指定 GC 线程数,其默认值为 CPU 核心数。
并行垃圾收集器适用于多核服务器,主要目标是增加吞吐量。因为对系统资源的有效使用,能达到更高的吞吐量:
并行垃圾收集器的几个重要JVM参数:
使用并行GC在多处理器(CPU核心数多)并且有大量内存的环境中,可以充分利用硬件资源以获取尽可能高的吞吐量,所以这种GC方式非常适合在后台计算类的应用,没有交互的场景。
并行GC中不同回收线程之间是如何协作对堆内存进行回收?
在并行GC中,不同的回收线程会同时工作来对堆内存进行垃圾回收。它们会协同工作以实现高效的垃圾收集。
在年轻代的垃圾回收过程中,会将堆内存分为多个区域(一般是2~16个),每个区域由一个线程负责进行垃圾回收。这些线程会同时进行垃圾标记和复制操作,以提高垃圾回收的效率。垃圾标记阶段会遍历对象图,标记出存活的对象,将存活的对象复制到另一个区域中。最后,回收线程会对其负责区域中的垃圾进行回收。
在老年代的垃圾回收过程中,各个回收线程会使用并行方式进行标记和清除操作,并行进行垃圾回收。垃圾标记阶段会遍历对象图进行标记,标记出存活的对象。然后,在清除阶段,垃圾回收线程会并行清理不再存活的对象,并整理堆空间来解决内存碎片问题。
在并行GC过程中,因为涉及到并行协作,所以需要一定的线程同步和协调机制来确保并发操作的正确性。同时,在进行并行垃圾回收时,也需要考虑到线程之间的负载平衡以及避免线程竞争和死锁等问题。
通过并行化的垃圾回收方式,可以充分利用多个处理器核心,提高垃圾回收的效率和整体吞吐量。然而,需要注意的是,并行化的垃圾回收也会引入一些额外的开销,如线程切换和同步开销。因此,在特定的应用场景中,需要根据实际情况进行性能测试和调优,以确定合适的垃圾收集策略。
对于一个4GB的内存堆,下面是一个基于并行GC(Parallel GC)的例子,涉及年轻代和老年代的内存分布:
年轻代内存分布:
老年代内存分布:
与串行GC相比,并行GC会使用多个线程并行进行垃圾回收,以提高内存回收的效率和吞吐量。
在年轻代的垃圾回收过程中,同时对Eden空间和Survivor区进行回收。当Eden空间和To区的内存占用达到一定阈值时,触发Minor GC,清理Eden空间和From区的无用对象,并将存活的对象复制到To区。
在老年代的垃圾回收过程中,多线程并行进行标记和清除操作。标记阶段会遍历老年代对象图,标记存活的对象。然后,在清除阶段,会并行清理不再存活的对象,并整理堆空间来解决内存碎片问题。
需要注意的是,并行GC的具体内存分布会受到具体的JVM参数配置和垃圾收集器策略的影响。使用相关监控工具和命令(如jstat、jmap等),可以获取更准确的内存使用情况和垃圾回收相关的数据。
链接:https://www.aliyundrive.com/s/CicYB9XtnEK
今天就到这里吧,感觉有用的小伙伴可以点个赞,你的支持就是我更新的最大动力!