JVM--垃圾回收

发布于:2025-03-16 ⋅ 阅读:(15) ⋅ 点赞:(0)

垃圾回收的概念 

垃圾回收主要针对的是堆中的对象,堆是一个共享的区域,创建的对象和数组都放在这个位置。但是我们不能一直的创建对象,也不是所有的对象能一直存放,如果不进行垃圾回收,内存迟早会耗尽,及时的垃圾回收能提高内存的利用率以及存储效率。

什么样的对象进行垃圾回收?

如果一个或多个对象没有任何的引用指向它了,那么这个对象现在就是垃圾,如果定位了垃圾,则有可能会被垃圾回收器回收。

如何定位垃圾?

引用计数法:一个对象被引用了一次,在当前对象头上递增一次引用次数,如果这个对象的引用次数为0,代表这个对象可以回收。

在创建对象时,对象对应的引用次数为1,如果后续给对象赋值NULL,则对象的引用次数会变为0,此时表明当前的对象是可以被垃圾回收的。

当对象间出现了循环引用时,引用计数法就会失效。会导致内存泄露

创建a和b之后,并且创建的对象之间有循环引用,则两个对象的堆内存的ref初始值为2,在设置对象a和b为null后,由于循环引用的存在,内存区域的ref为1,导致这两块内存区域一直不能回收

可达性分析算法

现在的虚拟机采用的都是通过可达性分析算法来确定哪些内容是垃圾。

  • Java虚拟机中的垃圾回收器采用可达性分析来探索所有存活的对象
  • 可达性算法的流程:扫描堆中的对象,看是否能够沿着GCRoot对象为起点的引用链找到该对象,找不到,表示可以回收

如上图所示,由于从GC Roots开始沿着引用链进行寻找,并不能找到X 和 Y,因此X和Y可以回收

哪些对象可以作为GC Root呢?

1.虚拟机栈(栈帧中的本地变量表)中引用的对象

2.方法区中类静态属性引用的对象

3.方法区中常量引用的对象

4.本地方法栈中JNI(即一般说的Native方法)引用的对象

垃圾回收算法

JVM垃圾回收算法有哪些?

标记清除算法

将垃圾回收分为2个阶段,分别是标记和清除。

1.根据可达性分析算法得出的垃圾进行标记

2.对这些标记为可回收的内容进行垃圾回收

标记清除算法的优缺点

优点:标记和清除的速度很快

缺点:碎片化较为严重,内存不连贯


复制算法

1.将内存划分为两个区域根据可达性分析算法得出的垃圾进行标记

2.将存活的对象复制到另一块内存区域。然后清理边界以外的垃圾


复制算法的优缺点

优点:在垃圾对象多的情况下,效率较高。清理后,内存无碎片。

缺点:分配的2块内存空间,在同一时刻,只能使用1个,内存的使用率较低

标记整理算法

1.根据可达性分析算法得出的垃圾进行标记

2.对这些标记为可回收的内容进行垃圾回收

3.清除之后,将存活的对象进行整理,向一端移动,然后清理边界意外的垃圾

优缺点同标记清除算法,解决了标记清除算法的碎片化的问题,同时,标记压缩算法多了一步,对象移动内存位置的步骤,其效率也有有一定的影响。

JVM的分代回收

堆的区域划分

在java8时,堆被分为了两份:新生代和老年代【1:2]

对于新生代,内部又被分为了三个区域。

  • 伊甸园区Eden,新生的对象都分配到这里
  • 幸存者区survivor(分成from和to)

Eden区,from区,to区[8:1:1]

对象回收分代回收策略
  • 新创建的对象,都会先分配到eden区
  • 当伊甸园内存不足,标记伊甸园与from(现阶段没有)的存活对象
  • 将存活对象采用复制算法复制到to中,复制完毕后,伊甸园和from内存都得到释放
  • 经过一段时间后伊甸园的内存又出现不足,标记eden区域to区存活的对象,将存活的对象复制from区
  • 当幸存区对象熬过几次回收(最多15次),晋升到老年代(幸存区内存不足或大对象会导致提前晋升)
MinorGC、Mixed GC、FulIGC的区别是什么?

MinorGC【youngGC】:发生在新生代的垃圾回收,暂停时间短(STW)

MixedGC:新生代+老年代部分区域的垃圾回收,G1收集器特有

FulIGC:新生代+老年代完整垃圾回收,暂停时间长(STW),应尽力避免

STW(Stop-The-World):暂停所有应用程序线程,等待垃圾回收的完战

JVM中的垃圾回收器

在jvm中,实现了多种垃圾收集器,包括:

  • 串行垃圾收集器:Serial GC、Serial Old GC
  • 并行垃圾收集器:Parallel Old GC、ParNew GC
  • CMS(并发)垃圾收集器:CMSGC,作用在老年代
  • G1垃圾收集器,作用在新生代和老年代

串行垃圾回收器

  • Serial和SerialOld串行垃圾收集器,是指使用单线程进行垃圾回收,堆内存较小,适合个人电脑
  • Serial 作用于新生代,采用复制算法
  • SerialOld 作用于老年代,采用标记-整理算法
  • 垃圾回收时,只有一个线程在工作,并且java应用中的所有线程都要暂停(STW),等待垃圾回收的完成。

并行垃圾收集器

  • ParallelNew和ParallelOld是一个并行垃圾回收器,JDK8默认使用此垃圾回收器
  • ParallelNew 作用于新生代,采用复制算法
  • ParallelOld 作用于老年代,采用标记-整理算法
  • 垃圾回收时,多个线程在工作,并且java应用中的所有线程都要暂停(STW),等待垃圾回收的完成。

CMS(并发)垃圾收集器


CMS全称ConcurrentMarkSweep,是一款并发的、使用标记-清除算法的垃圾回收器,该回收器是

针对老年代垃圾回收的,是一款以获取最短回收停顿时间为目标的收集器,停顿时间短,用户体验

就好。其最大特点是在进行垃圾回收时,应用仍然能正常运行。

为什么要进行重新标记?

可能出现一种情况,当X一开始没有在引用链上,但是在并发标记期间,某个对象对X引用,此时就不能对X进行回收,因此需要重新标记。

G1垃圾回收器

  • 应用于新生代和老年代,在JDK9之后默认使用G1
  • 划分成多个区域,每个区域都可以充当eden,survivor,old,humongous,其中humongous专为大对象准备
  • 采用复制算法
  • 响应时间与吞吐量兼顾
  • 分成三个阶段:新生代回收(stw)、并发标记(重新标记stw)、混合收集
  • 如果并发失败(即回收速度赶不上创建新对象速度),会触发FullGC
垃圾回收的流程

YoungCollection(年轻代垃圾回收)

1.初始时,所有区域都处于空闲状态

2.创建了一些对象,挑出一些空闲区域作为伊甸园区存储这些对象

3.当伊甸园需要垃圾回收时,挑出一个空闲区域作为幸存区,用复制算法复制存活对象,需要暂停用户线程

在标记的过程中或者是在复制的过程中,都需要触发STW

4.随着时间流逝,伊甸园的内存又有不足,将伊甸园以及之前幸存区中的存活对象,采用复制算法,复制到新的幸存区,其中较老对象晋升至老年代

YoungCollection+ConcurrentMark(年轻代垃圾回收+并发标记)
5.当老年代占用内存超过阈值(默认是45%)后,触发并发标记,在老年代中找到存活的对象,这时无需暂停用户线程

6.并发标记之后,会有重新标记阶段解决漏标问题,此时需要暂停用户线程。

MixedCollection(混合垃圾回收)
混合收集阶段中,参与复制的有eden、survivor、old。此时不会对所有老年代区域进行回收,而是根据暂停时间目标优先回收价值高(存活对象少)的区域(这也是GabageFirst 名称的由来)。复制完成,内存得到释放。进入下一轮的新生代回收、并发标记、混合收集。

混合收集可能会持续多次。

新生代中存活的对象会被复制到最新的幸存区,之前的幸存区以及老年代中存活的对象,将会放在一个老年代中。

强引用、软引用,弱引用,虚引用的区别

强引用:只有所有GCRoots对象都不通过【强引用】引用该对象,该对象才能被垃圾回收。只要所有GC Roots能找到,就不会被回收

软引用:需要配合SoftReference使用,当垃圾多次回收,内存依然不够的时候会回收软引用对象

弱引用:需要配合WeakReference使用,只要进行了垃圾回收,就会把弱引用对象回收

虚引用:必须配合引用队列使用,被引用对象回收时,会将虚引用入队,由ReferenceHandler线程调用虚引l用相关方法释放直接内存(虚引用的外部资源)


网站公告

今日签到

点亮在社区的每一天
去签到