首页
学习
活动
专区
圈层
工具
发布

GC

作者头像
瑞新
发布2020-07-07 21:14:32
发布2020-07-07 21:14:32
9410
举报

垃圾标记算法

解决

对象内存分配问题、回收分配给对象内存的问题

对象被判定为垃圾的标准

没有被其他对象引用

判定对象是否为垃圾的算法

引用计数算法

优缺点
缺点代码演示

对象实例相互引用,循环引用 主流的gc没用这种方法

可达性分析算法

离散数学的图论理解 从gc Root 向下搜索走过的路径,成为引用链。 存活标记为可达。 垃圾对象则不可达

可以作为GC ROOT的对象

垃圾回收算法

标记-清除算法

碎片化

不利于后来程序运行时,无法找到较大的连续内存分配

复杂算法

对象存活率低的场景 不会有碎片,每次对每个半区进行回收

商用虚拟机,多采用这种方法回收年轻代基本只有10%存活 年轻代

标记整理算法

在标记清除做了改进 解决空间碎片化问题

分带收集算法 主流

生命周期划分不同区域。采用不同垃圾回收算法

Minor GC年轻代垃圾复制算法

所有java出生的地方。申请的内存和存放都是在此处 Java对象一般不需要长久存活,朝生夕灭

每次gc年龄递增+1 通过调节年龄到老年代的参数,默认15岁

如何晋升至老年代

Full GC老年代

一般老年代回收,会伴随年轻代。 Full 比 Minor 执行慢10倍左右,但执行频率低

触发回收Full 老年代空间不足。 jdk1.7及以前永久代空间不足 CMS GC 同时。年轻代放不下,老年代也放不下。

jdk7及以前 对比 jdk8

jdk8将永久代删掉了 年轻代:存活率低,采用复制算法 老年代:存活率高,采用标记整理、清除

参数调优

空间分配:老:新大概2:1

新生代垃圾收集器

其他线程等待gc线程

安全点

什么是安全点?

JVM的快照下分析,其他线程停止等待gc线程。 不能存在gc分析过程中对象引用状态还在不停变换,因此分析结果在某个点具有确定性,这个点叫做安全点。 程序必须到达安全点才会停顿下来。 安全点太多,GC 过于频繁,增大运行时负荷;安全点太少,GC 等待时间太长。

JVM运行模式

Server 启动慢,重型,运行稳定后变快 Client 启动快,轻型,运行后,没server快

Serial收集器

减少gc线程等待时间(系统停顿时间)适合交互 在程序启动时可以设置 指定 收集器 Java最基本历史最悠久的收集器 jdk1.3.1以前是Java虚拟机年轻代的唯一选择

Server模式下的年轻代首选 除了Serial 只有ParNew与CMS配合使用

多线程 关注系统吞吐量,适合后台计算。 如果对收集器调优不熟悉,可以在启动时加上自适应 调节策略,把内存管理和调优任务交给虚拟机执行。

老年代收集器

jdk6之后提供 比较尴尬的是 在此之前,如果年轻代选择了Parallel Scavenge,老年代必须选择Serial Old收集器 。由于老年代服务端单线程性能上的拖累。使年轻代Parallel Scavenge未必能达到吞吐量最大化的效果。单线程的老年代无法充分利用年轻代多线程cpu的处理能力。 因此在老年代很大,硬件高级的环境中。甚至没有ParNew和CMS的组合给力。 直到Parallel Old出现,可以与Parallel Scavenge组合吞吐量优先收集器有了名副其实的组合。 适用:吞吐量、cpu敏感的场合

CMS占据着垃圾回收老年代的半壁江山 垃圾回收线程几乎和用户线程同时工作 但是还不能做到完全不需要(系统停顿时间),只是尽可能的缩短了应用时间 适用场景:对停顿比较敏感,需要更大的内存和cpu ,更牛的硬件 JVM中有很多存活时间相对较长的对象,可以用CMS 只扫描根直接关联的节点 缺点:标记清除,碎片化严重

及适用于年轻代又适老年代

用于替换掉JDK5中的CMS收集器

垃圾收集器之间的联系

CMS 和 G1使用了新的独立框架,而其他的共用框架类似

面试题

Object的finalize()方法的作用是否与C++的析构函数作用相同

C++析构函数,调用时机确定,对象离开作用域就会被清除掉 Java的finalize(),具有不确定性,当垃圾回收器宣告一个对象死亡时至少经过两次标记过程。 可达性分析之后发现,当没有和GC ROOT相链接的引用链,会被第一次标记。并且判断是否执行finalize方法,如果对象覆盖finalize()方法且未被引用, 这个对象就会被放置在F-Queue队列中,并在稍后由虚拟机自动建立的低优先级finalize线程去执行触发finalize()方法 。(由于优先级比较低,不承诺等待其运行结束,方法执行了随时可能被终止)给对象创造了最后一次重生的机会

不建议使用:由于运行的不确定性较大,无法保证各对象的调用顺序,同时运行代价相当高昂。

代码证明

Java的强引用、软引用、弱引用、虚引用,有什么用?

强 宁可终止也不回收

软 内存不够用再回收 适用:内存缓存 包装使用:SoftReference< String> 配合引用队列使用:

弱 见到就回收 垃圾回收优先级低 适用:偶尔使用 WeakReference< String >

必须和队列联合使用。软引用、弱引用也可以用此种方式 哨兵作用:判断是虚引用是否加入队列中,知道gc是什么时候执行的

综上比较

类层次结构

引用队列

依赖节点之间类似链表 链表的容器,其自己仅存储当前的head节点。后面的节点由referent.next()链接 除强引用,其他引用在gc后,将引用对象放在ReferenceQueue

追源码

referent新创建对象的引用 queue类似链表结构 next指向下一个引用

引用对象放在ReferenceQueue代码示例

开始时queue为空 normal打印载入的名字 weak没有打印 gc垃圾回收 weak载入到了主方法内,此时name被垃圾回收所以输出为null

对ReferenceQueue进行监控,如果有对象被回收,那么响应的Reference对象就会被放到Queue里面,就可以拿Refernce做一些事情。 如果不带Queue,就要不断的轮询Reference,通过不断的判断里面的get方法是否返回null ,来判断是否被回收。 通过Get方法来判断返回对象是否为空并不适用虚引用,因为此get方法返回值一直为null,只能通过Queue来判断

弱引用哨兵功能

主方法

输出

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/03/26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 垃圾标记算法
    • 解决
    • 对象被判定为垃圾的标准
    • 判定对象是否为垃圾的算法
      • 引用计数算法
      • 可达性分析算法
  • 垃圾回收算法
    • 标记-清除算法
    • 碎片化
    • 复杂算法
    • 标记整理算法
    • 分带收集算法 主流
      • Minor GC年轻代垃圾复制算法
      • 如何晋升至老年代
      • Full GC老年代
    • jdk7及以前 对比 jdk8
    • 参数调优
  • 新生代垃圾收集器
    • 其他线程等待gc线程
    • 安全点
    • JVM运行模式
    • Serial收集器
    • 老年代收集器
    • 及适用于年轻代又适老年代
    • 垃圾收集器之间的联系
  • 面试题
    • Object的finalize()方法的作用是否与C++的析构函数作用相同
    • Java的强引用、软引用、弱引用、虚引用,有什么用?
    • 综上比较
    • 类层次结构
    • 引用队列
      • 追源码
    • 引用对象放在ReferenceQueue代码示例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档