简述jvm的垃圾回收策略

1. 什么是jvm的垃圾回收?

垃圾回收(Garbage Collection)通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了。比如Smalltalk,Eiffel等编程语言也集成了垃圾收集器的机制,java语言是目前使用最多的依赖于垃圾收集器的语言。

java语言会自动管理回收不再引用的内存数据,是通过垃圾回收机制来完成的。它提供了内存管理的机制,使得应用程序不需要在关注内存如何释放,内存用完后,垃圾收集会进行收集,这样就减轻了因为人为的管理内存而造成的错误。

jvm中,程序计数器、虚拟机栈、本地方法栈都是随线程而生随线程而灭,栈帧随着方法的进入和退出做入栈和出栈操作,实现了内存的自动清理。因此,内存的垃圾回收主要集中于java堆和方法区中,在程序运行期间,这部分内存的分配和使用都是动态的。

GC的过程:当系统在创建对象的时候,即当我们使用new关键字创建一个对象的时候,GC就开始监控对象的地址、大小以及使用状态。一般情况下,Java的GC机制都有特定的回收算法,GC通常会使用有向图的方式来记录堆中的所有对象,通过此种方式确定哪些对象是“可达的”,而哪些是“不可达的”。当GC判断一些对象不可达的时候,GC就有责任回收相关内存空间。但是,因为平台的不同,往往在调用System.gc()的时候,存在太多不确定性,可以这样认为,当程序调用了System.gc()过后,仅仅是程序向JVM发送了请求,至于JVM究竟在什么时候进行垃圾回收,不同的平台不一样。

GC在JVM中通常是启动了一个新的进程或者一组新的进程,它本身和Java用户程序一样需要占用heap空间,运行时也占用CPU。设计GC的时候,必须要在停顿时间和回收率之间进行权衡,原因在于它本身占用了Heap,如果GC运行时间太长,用户就会感觉到Java程序本身会有一定的停顿,如果运行时间太短,则有很多内存没有回收,使得程序里面创建的Java对象占用了大量的内存。

2. jvm如何判断一个对象是否存活?

垃圾回收方法的作用是找到那些"要回收的垃圾", 即那些不再被任何途径使用的对象。
判断对象是否存活,一般有两种方式:
引用计数法

这个方法的实现是,给对象添加一个引用计数器,每当一个地方引用这个对象时,计数器的值就会加1;当一个地方的引用失效时,计数器的值就会减1。当一个对象的计数器的值为0时,就说明这个对象不再被使用了。

优点:

  • 简单。
  • 执行效率高。

缺点:

  • 无法检测出循环引用:如果一个对象A持有对象B,而对象B也持有一个对象A,这种情况下对象A与对象B的计数器的值恒大于0,会使得GC永远无法回收这两个对象。
  • 开销大。

主流的jvm并不是通过引用计数法来判定对象是否是存活的。

可达性分析法

这个方法的实现是,通过一系列成为“GC Roots”的对象作为起始点;从这些节点向下搜索,搜索所走过的路径成为引用链;当从一个对象到GC Roots之间没有任何引用链,也就是说GC Roots到这个对象不可达时,就证明这个对象是不可用的。

在Java中可以作为GC Roots的对象包括:

  • 虚拟机栈中引用的对象
  • 方法区中静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI(Native方法)引用的对象

优点:

  • 更加精确严谨,可以检测出循环引用。

缺点:

  • 实现复杂
  • 效率低
  • 分析过程需要GC停顿,

3. jvm如何回收垃圾?

jvm采用的垃圾回收算法有:

标记-清除

算法分为标记和清除两个阶段:第一阶段是每当找到一个存活对象,就进行标记,第二阶段是清除掉所有未被标记的对象。这个是最基础的回收算法,因为其它的回收算法都是基于这个算法进行优化改进而产生的。
特点:标记和清除阶段的效率不高;容易产生空间碎片。
mark_sweep
复制
将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存使用完时,就这这一块中还存活着的对象复制到另外一块中,再把已使用过的内存空间一次清理掉。
特点:不用考虑内存碎片的问题;将内存缩小为原来的一半,持续复制长生存期的对象导致效率较低。
copy
标记-整理
算法分为标记和整理两个阶段:第一阶段和标记-清除算法是一样的,标记所有活着的对象,第二阶段和标记-清除算法是不一样的,不是直接对回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
mark_compact
分代收集算法
这种算法的基本假设是:绝大多数的对象的生命周期都非常短暂,存活时间短。
把java堆分为新生代和老年代,根据各个年代的特点采用最合适的回收算法。所有新生成的对象首先都是放在新生代的。新生代的目标就是尽可能快速地回收掉那些生命周期短的对象。老年代中存放经历了多次垃圾回收后仍然存活的对象,这些对象的生命周期较长。

  • 在新生代中,每次垃圾回收时,都会发现大量对象死去,只有少量存活,就采用复制算法,只要复制出少量存活对象就可以完成回收,成本较低。
  • 在老年代中,对象存活率高、没有额外空间对它进行分配担保,就必须采用标记-清理或标记-整理算法来回收。

4. jvm中的垃圾回收器

如果说收集算法是内存回收的方法论,垃圾收集器就是内存回收的具体实现。

Serial收集器
串行收集器是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收。新生代、老年代使用串行回收;新生代复制算法、老年代标记-压缩;垃圾收集的过程中会Stop The World(服务暂停)。

ParNew收集器
ParNew收集器其实就是Serial收集器的多线程版本。新生代并行,老年代串行;新生代复制算法、老年代标记-压缩。

Parallel收集器
Parallel Scavenge收集器类似ParNew收集器,Parallel收集器更关注系统的吞吐量。可以通过参数来打开自适应调节策略,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大的吞吐量;也可以通过参数控制GC的时间不大于多少毫秒或者比例;新生代复制算法、老年代标记-压缩。

Parallel Old 收集器
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。这个收集器是在JDK 1.6中才开始提供。

CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用都集中在互联网站或B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器是基于“标记-清除”算法实现的。

G1收集器
G1是目前技术发展的最前沿成果之一,HotSpot开发团队赋予它的使命是未来可以替换掉JDK1.5中发布的CMS收集器。

参考资料

夜月升-JVM垃圾回收策略(转载/整理)
JVM调优总结
GC算法 垃圾收集器

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

willwaywang6

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

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

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

打赏作者

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

抵扣说明:

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

余额充值