1. 判断对象可以被回收

1.1 引用计数法

给对象添加一个引用计数器,每当用一个地方引用它时,计数器加一;当引用失效时,计数器减一,计数器为0的对象就是不可能再被使用的。

存在的弊端:循环引用,如下图中A对象和B对象仅仅只是被彼此引用了,而不会被其它地方所引用,但是存在引用又无法进行回收,这就存在无辜的内存消耗。

1.2 可达性分析算法

通过一系列称为“GC Root” 的对象作为起始点,从这些节点往下找,搜索走过的路程称为引用链,当一个对到GC Roots没有任何引用链时,说明这个对象是不可用的,那么他们就会被判断成可回收的对象。

1.2.1 GC Root 对象

Java中的GC Root 对象:

  1. 虚拟机栈中引用的对象
  2. 方法区中类静态属性引用的对象
  3. 方法区中常量引用的对象
  4. 本地方法栈中引用的对象

使用MAT查看运行项目的GC Root 对象:

1.3 四种引用

  1. 强引用:最普遍存在的,只要沿着GC Root 对象的引用链找到就不会被垃圾回收;
  2. 软引用:还有用但非必须的对象,没有强引用对象引用它,并且内存不足时就可能会被回收;
  3. 弱引用:非必需对象的,没有强引用引用时触发垃圾回收就会被回收;
  4. 虚引用:有无虚引用存在不会对对象生存时间造成影响,也无法通过虚引用获取对象实例;虚引用的目的是能够在对象被回收时收到一个系统通知。比如:ByteBuffer,GC回收直接内存,需要引用Cleaner对象来触发Unsafe类的释放内存方法;
  5. 终结器引用:所有对象都有一个finallize()方法,当没有强引用对象引用时,JVM会帮助当前对象创建虚拟机引用,当前对象被垃圾回收时,会把终结器引用加入到引用队列,再由其它线程找到这个终结器引用对象,再调用当前对象的finallize()方法,再次GC时会把当前对象回收。

如图:
A1对象:被B对象和A对象两个GC Root 引用不会被垃圾回收;只有引用都断掉才能会被回收。
A2对象:被C对象间接软引用也被B对象引用;如果B对象断开引用,触发垃圾回收时,且内存不够就会回收A2对象。
A3对象:被C对象间接弱引用也被B对象引用;如果B对象断开引用,触发垃圾回收时会回收A3对象。

1.4 引用队列

如果配合了引用队列来使用软引用和弱引用,当软(弱)引用对象所引用的对象被回收时软(弱)对象就会进入到以用队列中去,引用队列可以释放软(弱引用)对象。
虚引用和终结器引用都必须要搭配引用队列来使用,当被虚引用引用的对象回收时,虚引用对象就会进入到引用队列中,

2. 垃圾回收算法

2.1 标记清除

分为“标记”和“清除”两个阶段:首先要标记出所有需要回收的对象,在标记完成后统一回收所有的被标记对象。

特点:

  1. 速度快:清除过程只需要记录内存的起始和结束地址;
  2. 容易产生内存碎片:清除产生的内存空间不是连续的,无法放下内存较大对象。

2.2 标记整理

分为“标记” 和 “整理部分”,整理之后会将存活的对象都向一端移动,然后直接清理掉边界以外的内存,从而解决内存碎片的问题。

特点:

  1. 没有内存碎片
  2. 效率低:移动对象需要考虑对象引用相关问题。

2.3 复制

它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。

把FROM区存活的对象复制到TO区,并且在复制过程中也会进行整理,不会产生碎片内存,等到清空完成之后交换FROM和TO,

清理之前:

完成清理之后(FROM已经换成了TO区):

特点:

  1. 不会产生碎片
  2. 占用双倍的内存空间

3. 分代回收

JVM将堆内存划分为如下区域:新生代存放存活时间比较短的对象,老年代存放比较有价值的对象;针对不同的区域采用不同的算法,对垃圾回收施行更有效的管理。

3.1 分代回收过程

创建对象时,会放到伊甸园:

伊甸园无法再容纳新对象时,会触发一次新生代的垃圾回收Minor GC,采用可达性分析,将伊甸园和FROM中存活的对象使用copy复制到TO区,并且将这些对象的寿命加一,交换FROM和TO的位置,将伊甸园中的已经死亡的对象清空。
Minor GC 会引发 Stop the world,将其它用户的线程都暂停,等到复制和回收都完成之后(因为涉及复制相关,如果对象移动就可能会造成混乱),再启动其它线程。

这样就可以再向伊甸园存放新的对象,然后再进行上诉过程,当一个对象经历过多次Minor GC 之后,他的“寿命”达到一个固定的阈值(最大值15),就会将这个对象晋升到老年代,

当老年代空间不足会先尝试触发Minor GC,如果空间仍然不足,会触发Full GCFull GCStop the world ** 时间会更长,会将整个新生代和老年代都进行清理。

如果触发了
Full GC** 之后堆空间仍然不足就会抛出堆内存溢出异常java.lang.OutOfMemoryError: Java heap space

3.2 GC相关参数

含义 参数
堆容量最大值 -Xmx
堆容量初始值 -Xms
新生代容量 -Xmn
幸存区比例(动态) -XX:InitialSurvivorRatio=ratio
幸存区比例 -XX:SurvivorRatio=ratio
晋升阈值 -XX:MaxTenuringThreshold=threshold
晋升详情 -XX:+PrintTenuringDistribution
GC详情 -XX:+PrintGCDetails -verbose:gc
Full GC 前 Minor GC -XX:+ScavengeBeforeFullGC

3.3 实战演示GC过程

添加参数:-Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc
堆内存最大为20M,新生代为10M,那么老年代也是10M

     ArrayList<byte[]> list = new ArrayList<>();list.add(new byte[_7MB]);

当新生代内存不够时会触发Minor GC

         ArrayList<byte[]> list = new ArrayList<>();list.add(new byte[_8MB]);

当新生代的内存不足够放下一个大对象时,对象会直接晋升到老年代中,不会引起新生代的GC

         ArrayList<byte[]> list = new ArrayList<>();list.add(new byte[_8MB]);list.add(new byte[_8MB]);

当老年代和新生代都满的时候会先触发Minor GC 然后再触发 Full GC 如果此时还不能创建新对象就会抛出异常。

  new Thread(()->{ArrayList<byte[]> list = new ArrayList<>();list.add(new byte[_8MB]);list.add(new byte[_8MB]);}).start();

其它的线程创建对象时如果堆内存溢出不会影响主线程

4. 垃圾回收器

4.1 串行

单线程垃圾回收器,运行时其它线程都暂停,
适合堆内存较小的个人电脑。

开启串行回收器:-XX:+UseSerialGC = Serial + SerialOld,新生代采用copy算法,老年代采用复制-整理算法。

普通线程在一个安全点停下来,保证对象的地址不会改变,普通线程进入阻塞状态,等待垃圾回收线程回收完毕,在变回到运行态。

4.2 吞吐量优先

多线程垃圾回收器,在单位时间Stop the world的时间最短。指一定时间内触发的GC的总和时间最短。
适合堆内存较大,多核CPU来支持,服务器电脑

在JDK1.8下默认使用的是吞吐量优先垃圾回收器,等线程达到安全点后会开启多个线程同时回收,默认情况下线程的数量是基于计算机本身的核心数的,可以通过:

  1. -XX:ParallelGCThreads = n :来设置线程数量;
  2. -XX:+UseAdaptiveSizePolicy:开启自适应调整新生代大小;
  3. -XX:GCTimeRatio=ratio:调整垃圾回收时间和总时间的占比,计算公式:1 / (1 + ratio),默认99,一般使用19,如果达不到这个目标就会尝试调整堆的大小,从而达到吞吐量的提高。
  4. -XX:MaxGCPauseMills = nms:最大暂停毫秒数,默认200ms。

4.3 响应时间优先

多线程垃圾回收器,使单次回收Stop the world的时间尽可能的短。工作在老年代
适合堆内存较大,多核CPU来支持。

  1. -XX:+UseConMarkSweepGC ~ -XX+UseParNewGC ~ SerialOld,开启方式,用户线程和垃圾回收线程同时进行。
  2. -XX:ParalleGCThreads=n ~ -XX:ConGCThreads = threads:指定并发线程并行线程,一般设置并行线程为并发的1/4来执行垃圾回收,其它的线程正常运行。
  3. -XX:CMSInitiatingOccupancyFraction=precent:设置CMS垃圾回收的内存占比,;因为在垃圾回收过程中会产生新的垃圾称为浮动垃圾,需要预留出来一部分空间给浮动垃圾。
  4. -XX:+CMSScavengeBeforeRemark:在重新标记之前,对新生代做一次垃圾回收;在重新标记过程中,需要对整个堆内存进行扫描,新生代中对象较多,并且有部分需要回收,对他们进行扫描会影响性能。

工作流程:当老年代内存不足时会将所有的线程在安全点停下来,垃圾回收线程进行初始标记,标记完成之后其它线程可以重新运行,垃圾回收线程并发标记,等到并发标记完成之后,需要Stop the World,所有线程一块进行标记,标记完成之后,垃圾回收线程执行并发清理,其它线程同时运行。

因为需要部分线程来进行垃圾回收,所以对程序的吞吐量有一定的影响。

5. G1垃圾回收器

Garbage First ,不过一般发音称Garbage One。
在JDK9中为JVM默认的垃圾回收器,取代了之前的CMS垃圾回收器。
开启G1:-XX:+UseG1GC

使用场景:

  1. 注重吞吐量和低延迟,默认的暂停目标是200ms;最大暂停时间:-XX:MaxGCPauseMill=time
  2. 超大堆内存,将堆内存划分为多个相等的区域;设置区域大小:-XX:G1HeapRegionSize=n,值只能是2的倍数(或者1)。
  3. 整体上是标记+整理算法,两个区域之间是复制算法。

5.1 垃圾回收阶段

三个垃圾回收阶段是循环运行的。

5.1.1 Young Collection

新生代垃圾回收,G1将堆内存划分称大小相等的多个区域,每个区域都可以独立作为伊甸园、FROM、TO。当作为伊甸园的区域被占满是,会触发Young Collection,会触发STW

当触发了新生代回收时,会将幸存的对象复制到幸存区。

再次触发Young Collection时,年龄不够的存活对象会被复制到其它的幸存区 ,当对象存活时间足够久之后会晋升到老年代。

5.1.2 Young Collection + Concurrent Mark

新生代垃圾回收时会进行GC Root初始标记;老年代的堆空间比例达到一定阈值时,会进行并发标记。
配置阈值:-XX:InitiatingHeapOccupancyPercent=n默认为45%。

5.1.3 Mixed Collection

混合回收会对伊甸园、幸存区、老年代进行统一回收。
新生代的晋升和回收和上方回收一样。
不同的是针对于老年代的回收,如果暂停时间不足,G1会基于设置的最大暂停时间有选择的回收老年代中的垃圾对象,因此被称为Garbage First。相反如果时间足够就会回收全部。
设置最大暂停时间:-XX:MaxGCPauseMillis=ms

5.1.4 Young Collection 跨代引用

可达性分析需要找到其对象的根对象,如果新生代对象的根对象位于老年代,但老年代存活对象非常多,全部遍历效率低。因此采用了一个Card Table 技术,如果其中有对象引用了新生代对象,就标记为脏卡,这样在进行GC Root时直接去脏卡里面找,提高效率。
伊甸园中通过Remember Set 记录脏卡的位置,变更时也会异步更新Remember Set


脏卡引用:

5.1.5 Remark

如图普通标记阶段所示:

  1. 黑色表示重新标记完成,并且有对象以用它;
  2. 灰色正在标记处理;
  3. 白色暂未处理;
  4. 处理之后如果没有引用也是白色;
  5. 全部处理完毕会清除白色的对象。

    但由于标记是异步处理的,如果在异步处理过程中,对象的引用地址改变,会造成意外回收被强引用的对象。

Remark重新标记阶段:只要对象的引用发生了变化,就会执行写屏障pre-write barrier指令,将对象加入到队列satb_mark_queue中,再等待处理。等到整个并发标记结束了之后,会进行重新标记,暂停所有的用户线程,把队列中的对象取出重新检查。

5.1.6 字符串去重

在JDK 8u20版本之后引入了字符串去重。将所有新分配的字符串放入一个队列,当新生代回收时,G1并发检查是否有字符串重复,如果值一样就引用相同的。
开启:-XX:+UseStringDeduplication

优点:节省内存;
缺点:占用CPU时间,新生代垃圾回收时间增加。

5.1.7 类卸载

在JDK 8u40之后,当所有的对象都经过并发标记后,如果一个类加载器的所有类都不再使用,就卸载它的所有类。
开启:-XX:+ClassUnloadingWithConcurrentMark

5.1.8 回收巨型对象

当一个对象大于分区一般时,称为巨型对象;G1不对拷贝巨型对象,且会优先考虑回收。如果老年代中有没有“卡”引用了巨型对象,该巨型对象就会被新生代回收时回收掉。

如图中H:

没有老年代引用的巨型对象:

Java虚拟机之垃圾回收相关推荐

  1. 学习笔记【Java 虚拟机②】垃圾回收

    若文章内容或图片失效,请留言反馈.部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 总目录 学习笔记[Java 虚拟机①]内存结构 学习笔记[Java 虚拟机②]垃圾回收 学习笔记[Java ...

  2. java虚拟机多久触发垃圾回收_每日一问:讲讲 Java 虚拟机的垃圾回收

    昨天我们用比较精简的文字讲了 Java 虚拟机结构,没看过的可以直接从这里查看: 每日一问:你了解 Java 虚拟机结构么? 今天我们必须来看看 Java 虚拟机的垃圾回收算法是怎样的.不过在开始之前 ...

  3. Java虚拟机之垃圾回收详解一

    Java虚拟机之垃圾回收详解一 Java技术和JVM(Java虚拟机) 一.Java技术概述: Java是一门编程语言,是一种计算平台,是SUN公司于1995年首次发布.它是Java程序的技术基础,这 ...

  4. 浅析Java虚拟机的垃圾回收机制(GC)

    目录 一.垃圾回收机制(Garbage Collection) 二.对象回收的时机 引用计数法 可达性分析算法 三.垃圾回收算法 标记-清除算法 标记-复制算法 标记-整理算法 新生代.老年代.永久代 ...

  5. Java虚拟机:垃圾回收机制与垃圾收集器

    一.垃圾回收机制: 1.垃圾回收的过程: JVM内存区域的程序计算器,虚拟机栈.本地方法栈的生命周期是和线程同步的,随着线程的销毁而自动释放内存,所以只有堆和方法区需要GC,方法区主要是针对常量池的回 ...

  6. ReviewForJob——java虚拟机的垃圾回收策略(个人总结)

    理解jvm的垃圾回收策略,需要解决以下3个问题 问题1:哪些内存需要回收? 问题2:什么时候进行回收? 问题3:怎样来回收? [解决问题1]哪些内存需要回收? jvm的内存区域有5大块: 1)程序计数 ...

  7. 深入理解java虚拟机之——垃圾回收(垃圾判断,垃圾收集算法,垃圾收集器)

    java与C++之间有一道动态内存分配和垃圾收集的"墙",墙里面的人想出来,墙外边的人想进去,或许只有骑在墙上才能清楚的了解,墙内墙外都是牢笼. 上面一句出自<深入理解jav ...

  8. java虚拟机、垃圾回收、多线程

    虚拟机,我们都知道Java程序运行在虚拟机上,虚拟机又和操作系统打交道,最终通过二进制指令操纵电子电路运行.完成数据的读取,存储,运算和输出. 虚拟机在加载.class文件的时候,会在内存开辟一块区域 ...

  9. 深入理解Java虚拟机——JVM垃圾回收机制和垃圾收集器详解

    一:概述 说起垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联系起来.在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,顾名思义,垃圾回收就是释 ...

最新文章

  1. 效率提升多倍, 推荐值得收藏40 个命令总结
  2. 一文读懂语音识别技术原理
  3. python:urllib2.URLError urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed
  4. NHibernate快速起步
  5. VTK:Picking之HighlightPickedAct
  6. java getidentifier_android – 如何使用getResource.getIdentifier()获取布局?
  7. python面向对象编程(2)
  8. sudo echo x **.** 时 base: : Permission denied
  9. python最小值最大化和最大值最小化_OJ 21658::Monthly Expense(二分搜索+最小化最大值)...
  10. 软件测试-黑盒测试方法(一)---等价类划分、边界值、因果图、判定表
  11. selenium模拟登录QQ空间
  12. 淘宝R2去模糊化+聚石塔+奇门
  13. matlab 反走样,如何在python中使用Matlab的imresize
  14. 第八章 界面外观——Qt
  15. 以太坊区块链入门之实现简单DApp开发
  16. [WVR系列路由器] 微信连Wi-Fi功能使用指南
  17. android 相机闪光灯,在Android中使用相机闪光灯闪烁
  18. SurfaceView 加速 开启硬件加速
  19. 看不懂别做爬虫-----python爬虫实战---大众点评评论
  20. Tomcat打破双亲委派模型

热门文章

  1. 交流永磁同步电机的弱磁控制
  2. word空白页删除不掉
  3. ArcGIS JS 版军事标绘图(燕尾箭头、钳击箭头、集结地)扇形等自定义图形
  4. echarts广东省地图数据显示
  5. 树莓派设置WiFi上网
  6. 出租车智能终端与外设通讯实践
  7. android10手机众筹,世界上最小的Android 10手机海外众筹,竟是来自中国?
  8. 高德地图的缩放和位移监听
  9. 三体运动——基于MWORKS.Sysplorer研究初值对混沌系统数值求解的影响
  10. html鼠标右键功能,检查鼠标右键功能