【JVM】垃圾回收入门

一、先认识下,你的jvm使用的是什么垃圾回收器

 

回收器回收对象和算法回收器类型
Serial新生代,复制算法单线程(串行)
Parallel Scavenge新生代,复制算法并行的多线程回收器
ParNew新生代,复制算法并行的多线程收集器
Serial Old老年代,标记整理算法单线程(串行)
Parallel Old老年代,标记整理算法并行的多线程回收器
CMS老年代,标记清除算法并发的多线程回收器
G1跨新生代和老年代:标记整理+化整为零并发的多线程回收器
[root@VM-12-4-centos ~]# java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=30109632 -XX:MaxHeapSize=481754112 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC 
java version "1.8.0_212"
Java(TM) SE Runtime Environment (build 1.8.0_212-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.212-b10, mixed mode)



[root@node ~]# jmap -heap 971
Attaching to process ID 971, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.212-b10

using thread-local object allocation.
Parallel GC with 2 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 989855744 (944.0MB)
   NewSize                  = 20971520 (20.0MB)
   MaxNewSize               = 329777152 (314.5MB)
   OldSize                  = 41943040 (40.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 125304832 (119.5MB)
   used     = 59405816 (56.65380096435547MB)
   free     = 65899016 (62.84619903564453MB)
   47.40903846389579% used
From Space:
   capacity = 10485760 (10.0MB)
   used     = 1290296 (1.2305221557617188MB)
   free     = 9195464 (8.769477844238281MB)
   12.305221557617188% used
To Space:
   capacity = 10485760 (10.0MB)
   used     = 0 (0.0MB)
   free     = 10485760 (10.0MB)
   0.0% used
PS Old Generation
   capacity = 41943040 (40.0MB)
   used     = 16824376 (16.04497528076172MB)
   free     = 25118664 (23.95502471923828MB)
   40.1124382019043% used

14890 interned Strings occupying 1287896 bytes.

二、为什么以前会出现新生代和老年代使用不同的垃圾回收算法

主要原因就是因为新生代和老年代的对象生存特性决定的

年轻代

用来存放新生的对象。

目标就是尽可能快速的收集掉那些生命周期短的对象(比如我们有可能在一个for循环中创建了大量对象,但是循环结束后,这些对象引用就失效)。


老年代

在年轻代中经历了多次(可设置,一般为15)垃圾回收后仍然存活的对象,就会被放到年老代中。

因此,可以认为年老代中存放的都是一些生命周期较长的对象。

三、垃圾回收算法

复制算法(Copying)

一般情况下,新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次MinorGC后,如果仍然存活,将会被移到Survivor区(一旦收集后,Eden就变成空的)。对象在Survivor区中每熬过一次MinorGC,年龄就会增加1岁,当他的年龄增加到一定程度时(默认是15岁),就会被移动到老年代中。因为年轻代中的对象基本都是朝生夕死,所以在年轻代的垃圾回收算法使用的是复制算法。

基本思想就是:将内存分为两块,每次只用其中一块,当这块内存用完,就将还活着的对象复制到另外一块上面。

优点:不会产生内存碎片

缺点:耗空间

如果对象的存活率很高,我们可以极端一点,假设是100%存活,那么我们需要将所有对象都复制一遍,并将所有引用地址重置一遍。复制这一工作所花费的时间,在对象存活率达到一定程度时,将会变的不可忽视。所以从以上描述不难看出,复制算法要想使用,最起码对象的存活率要非常低才行,而且最重要的是,我们必须要克服50%内存的浪费。使用复制算法的前提是90%的对象会死,要是回收的对象没有这么多就麻烦了。

标记清除算法(Mark-Sweep)

扫描空间根据可达性分析标记可回收的对象,打上标记。

扫描空间根据标记可回收的对象,进行清除。

 

优点:不需要额外的空间

缺点:空间节约了,碎片出来了。同时两次扫描,耗时严重;

详细表述:

1,首先,缺点就是效率低(递归与全堆对象遍历),而且在进行GC的时候,需要停止应用程序,这会导致用户体验非常差劲。

2,其次,这种方式清理出来的空闲内存是不连续的,这点不难理解,我们的死亡对象都是随机的出现在内存的各个角落的,清除后,内存的布局自然乱七八糟。为了应付这一点,JVM就不得不维持一个内存的空闲列表,也是一种开销。而且在分配数组对象的时候,寻找连续的内存空间会不太好找。

也就有了标记-整理算法,对内存不连续的内存空间进行整理。

标记压缩算法(Mark-Compact)或者叫标记整理算法

 

比标记清除多了一步整理的过程。

理论上,耗时最长(在垃圾回收的时候,程序不能动)。

优点:没碎片

缺点:需要移动对象的成本

唯一的缺点就是效率不高,不仅要标记所有存活的对象,还要整理所有存活对象的引用地址。从效率上来说,标记整理算法要低于复制算法。

没有最好的算法,只有最合适的算法 ,因此也印证了我们为什么要进行分代垃圾收集。

思考:CMS为什么没有使用标记整理?

四、那怎么知道对象有没有死(未被引用)

引用计数法

为每个对象添加一个引用计数器,用来统计指向该对象的引用个数。一旦某个对象的引用计数为0,则说明该对象已经死亡,便可以被回收。

具体实现方式:

如果有一个引用,被赋值为某一个对象,那么将该对象的引用计数加1。如果一个指向某衣蛾对象的引用,被赋值为其他值,那么将该对象引用计数减1。

对于引用计数法来说,除了需要额外的空间来存储计数器,以及频繁的更新计数器外,引用计数法无法处理循环引用

所以目前JVM虚拟机主流垃圾回收器采用的是可达性分析算法。 

根可达分析

将一系列被称为GC Roots的变量作为初始的存活对象合集,然后从该合集出发,所有能够被该合集引用到的对象,将其加入到该合集中,而不能被该合集所引用到的对象,宣告死亡。

哪些对象可以作为GCRoots?

1,虚拟机栈(栈桢中的局部变量区,也叫做局部变量表)中引用的对象。

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

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

4,本地方法栈中JNI(Native方法)引用的对象。

在多线程环境下,其他线程可能会更新已经访问过的对象中的引用,但是可达性分析线程没有同步到新内容,容易漏报和误报。漏报顶多损失部分垃圾回收的机会,误报则会导致垃圾回收器回收了仍然被引用的对象。

STW(Stop the world),停止其他非垃圾回收线程,直到完成垃圾回收。

五、扩展

当然,JVM垃圾回收的内容也远远不止这些,这里算是入门引导。

推荐阅读:

什么是STW以及CMS和G1优缺点? - 知乎

CMS与三色标记算法 - 知乎

java面试一日一题:细数java中的垃圾回收器 - 北漂程序员 - 博客园

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天都要有成长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值