深入理解JVM——虚拟机GC
对象是否存活
Java的GC基于可达性分析算法(Python用引用计数法),通过可达性分析来判定对象是否存活。这个算法的基本思想是通过一系列"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时(图论称之为不可达),则证明此对象是不可用的。
无论引用计数法,还是可达性分析都离不开“引用”的概念。Java将引用分为四种(强引用、软引用,弱引用,虚引用),这四种引用强度依次逐渐减弱。
strong reference强引用,垃圾收集器永远不会回收存在强引用的对象。(如Object obj = new object()就是一个强引用)
soft reference软引用,描述一些还有用但是并非必须的对象。系统将要发生内存溢出异常之前,将会把这些软引用对象列入回收范围中进行二次回收。如果这次回收之后还是不够内存,才会抛出内存溢出异常。
weak reference弱引用,也是用来描述非必须对象的,但是它的强度更弱。被弱引用的对象只能活到下一次GC发生之前。当GC发生,无论当前内存是否充足都会回收弱引用对象。
phantom reference虚引用(幽灵引用),是最弱的一种引用关系。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。
在可达性算法中不可达的对象,不会直接死亡,如果它还没有执行finalize方法,虚拟机将在一个优先级很低的线程中触发它的finalize方法(不保证完成),如果此时对象又将自己关联到引用链上,那么GC将把它移出“即将回收”的集合。
由于finalize方法只会被执行一次,所以这个“自救”过程也只会经历一次。
垃圾回收方法
1、标记清除法
首先标记所有需要回收的对象,然后统一回收所有要回收的对象。方法简单,但是效率不高,并且产生了很多内存碎片。
2、复制算法
将内存分为大小相等的两块,每次只使用一块。当一块的内存用完了,就将还存活的对象复制到另一块内存上,然后把使用过的那一半内存空间一次性清理掉。这样再分配内存时只需要移动堆顶指针,实现简单,运行高效。但是代价是实际可用内存缩小了一半,实在太高。
因为新生代大部分对象都是”朝生夕死“,所以虚拟机将内存分为1个Eden和2个Survivor空间,大小比例默认为8:1:1。当回收时,将Eden和Survivor中还存活着的对象复制到另一个Survivor空间上,然后清理掉Eden和刚才用过的Survivor空间。这样子就只需要牺牲10%的新生代内存。
分配担保:因为存在1个Survivor空间存放不了Eden和另一个Survivor空间的对象的情况,此时那些存活的对象由于无法放入该Survivor空间,将直接进入老年代。)
3、标记-整理算法
老年代对象存活率高,复制算法在这时候效率很低,而且老年代没有额外空间做分配担保,所以不适用。根据这种特点,有人提出了标记-整理算法。
首先标记所有要回收的对象,然后所有存活的对象都向一端移动,然后直接清理边界以外的内存。
4、分代收集算法
前面三个垃圾回收算法都算是铺垫,现在商业虚拟机的垃圾收集都采用”分代收集“。将Java堆分成新生代和老年代,新生代中每次GC有大量对象死去,只有少量存活,所以采用复制算法;老年代中对象存活率高,没有额外空间进行分配担保,就采用标记-清除或者标记-整理算法。
垃圾收集器

新生代:serial收集器
单线程,必须暂停其他所有工作线程(Stop The World),直到它收集结束。STW难以接受,但是简单高效。
新生代:parNew收集器
serial的多线程版本。server模式下首选,因为它可以和cms配合使用。
新生代:parallel scavenge收集器
专注于达到可控制吞吐量的收集器,主要适合后台运算而不用太多交互的任务。
老年代:serial old收集器
serial的老年代版本,单线程。使用标记-整理算法。
老年代:parallel old收集器
parallel scavenge的老年代版本。使用标记-整理算法。
老年代:cms收集器
经历四个阶段:
初始标记:需要STW,仅仅标记一下GC Roots能直接关联的对象,所以很快。
并发标记:进行GC Roots Tracing
重新标记:需要STW,修正并发标记期间因程序运行导致标记产生变动的那一部分对象的标记记录,时间比初始标记长,但是远比并发标记短
并发清除:清除对象
由于耗时最长的并发标记和并发清除过程,收集器线程都可以和用户线程一起工作,所以总体来说cms收集器的内存回收过程是和用户线程一起并发执行的,停顿很短。
缺点:cpu资源敏感,特别是cpu核数较少时;无法处理浮动垃圾;cms基于标记-清除算法,容易产生大量内存碎片。
G1收集器
最新的收集器,性能优秀,但是太复杂不再赘述。
内存分配和回收策略
对象优先在Eden分配,如果启动了TLAB,将按照线程优先在TLAB上分配。
当Eden不够空间时,虚拟机发起一次Minor GC(新生代GC)
大对象直接进入老年代
长期存活的对象将进入老年代(存活一次GC age+1,默认age 15时进入老年代)
Survivor空间中相同年龄所有年龄大小 的总和大于Survivor空间的一半 时,年龄大于等于该年龄的对象可以直接进入老年代
Minor GC时,虚拟机会检查老年代的剩余空间是否大于新生代对象总大小or历次晋升的平均大小,如果是那么就会进行Minor GC,否则认为老年代无法提供分配担保,进行Full GC。
深入理解JVM——虚拟机GC的更多相关文章
- Java工程师学习指南第6部分:深入理解JVM虚拟机
本文整理了微信公众号[Java技术江湖]发表和转载过的JVM虚拟机相关优质文章,想看到更多Java技术文章,就赶紧关注本公众号吧吧. JVM原理分析,看了都说好 JVM 深入学习:Java 解析 Cl ...
- 深入理解JVM虚拟机11:Java内存异常原理与实践
本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...
- 深入理解JVM虚拟机1:JVM内存的结构与消失的永久代
本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...
- 《深入理解JVM虚拟机》读书笔记
前言:<深入理解JVM虚拟机>是JAVA的经典著作之一,因为内容更偏向底层,所以之前一直没有好好的阅读过.最近因为刚好有空,又有了新目标.所以打算和<构架师的12项修炼>一起看 ...
- 进入JVM的世界:《深入理解JVM虚拟机》-- 思维导图
进入JVM的世界:<深入理解JVM虚拟机>-- 思维导图 之前一直都是零零散散的看了些JVM的知识,心想这样不行啊!于是便抽空看了一下这本神书,阅罢,醍醐灌顶.豁然开朗.真正的是知其然,更 ...
- 深入理解JVM虚拟机:(一)Java运行时数据区域
概述 JVM是Java语言的精髓所在,因为它Java语言实现了跨平台运行,以及自动内存管理机制等,本文将从概念上介绍JVM内存的各个区域,说明个区域的作用. JVM运行时数据区模型 Java虚拟机在执 ...
- 深入理解JVM虚拟机开篇:JVM介绍与知识脉络梳理
微信公众号[Java技术江湖]一位阿里 Java 工程师的技术小站.作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux.网络.多线程,偶尔 ...
- 推荐收藏系列:一文理解JVM虚拟机(内存、垃圾回收、性能优化)解决面试中遇到问题(图解版)
欢迎一起学习 <提升能力,涨薪可待篇> <面试知识,工作可待篇 > <实战演练,拒绝996篇 > 欢迎关注我博客 也欢迎关注公 众 号[Ccww笔记],原创技术文章 ...
- 深入理解JVM虚拟机(一):JVM运行时数据区
概述: JVM将内存的管理进行封装,使得开发人员不必关心内存申请.释放操作.但是在高级程序开发.复杂业务场景开发的时候,如果出现内存溢出的情况,对于开发人员而言就很难去分析出原因.所以还是很有必要去了 ...
随机推荐
- zookeeper学习day01
1.zkAPI:(借助闭锁来实现) 1)创建闭锁对象 2)创建zk对象 3)连接zk客户端(连接成功执行countDown方法) 4)执行await方法(保证链接成功) 5)zk对象调用对 ...
- VS2017离线安装与Oracle数据库开发环境搭建
记得之前使用VS2015打开老的MVC4项目,不能右键创建控制器和添加视图,让我非常不习惯!找遍了网络无果,最后只能回到VS2013,但我就是不喜欢用旧的VS,这是不是病... 1.将VS2017离线 ...
- MyBatis 源码分析系列文章导读
1.本文速览 本篇文章是我为接下来的 MyBatis 源码分析系列文章写的一个导读文章.本篇文章从 MyBatis 是什么(what),为什么要使用(why),以及如何使用(how)等三个角度进行了说 ...
- Django _VIEW视图_源码分析
Django _VIEW视图: 1. 点击as_view方法. 第二步: as_view () 为VIEW 类里定义的,到时候我们定义业务逻辑的类就继承这个VIEW类. view方法内返回的是disp ...
- PMS构造函数以及apk如何扫描
一.PackageManagerService构造函数 1.创建data目录下面以及文件(settings的构造函数),然后再添加6个SharedUserSetting 2.开始扫描并且解析APK 3 ...
- localStorage 存满了怎么办?
先来几道面试题 1.a.meituan.com 和 b.meituan.com 这两个域能够共享同一个 localStorage 吗? 2.在 webview 中打开一个页面:i.meituan.co ...
- 在word 2010中采用EndNote X7插入引用
本文只供入门操作,记于此以防自己忘记,或帮助走过路过的你解决一时之需,即便是只能帮助到一个人,我的辛苦也就没有白费. 用EndNote向Word中直接插入参考文献能极大的提高论文写作的速度.在此以En ...
- 写好Java代码的30条经验总结
成为一个优秀的Java程序员,有着良好的代码编写习惯是必不可少的.下面就让我们来看看代码编写的30条建议吧. (1) 类名首字母应该大写.字段.方法以及对象(句柄)的首字母应小写.对于所有标识符,其中 ...
- 课程四(Convolutional Neural Networks),第二 周(Deep convolutional models: case studies) —— 0.Learning Goals
Learning Goals Understand multiple foundational papers of convolutional neural networks Analyze the ...
- Linux编程 8 (挂载mount,查看磁盘df du,搜索grep,压缩zgip,归档tar)
一. 挂载存储媒体 linux文件系统将所有的磁盘都并入一个虚拟目录下,当使用新的存储媒体之前,需要把它放到虚拟目录下,这项工作称为挂载(mounting) 1.1 mount 命令 在linux上用 ...