JVM&GC
先回顾啥是JVM:
引用:
强引用(Strong Reference)
•默认的赋值语句可以生成一个强引用
•GC时不会被释放
软引用(Soft Reference)
•仅被java.lang.ref.SoftReference引用
•JVM内存不足时,会被释放(FGC)
弱引用(Weak Reference)
•仅被java.lang.ref.WeakReference引用
•GC时被释放
虚引用(Phantom Reference)
•仅被java.lang.ref.PhantomReference引用
•目的不是为了释放内存,而是为了跟踪内存释放,可用于替代finalize函数
工具:
1、什么是GC
GC,全称是 Garbage Collection
(垃圾收集)或者 Garbage Collector
(垃圾收集器)。
研究 GC 的主要原因是 GC 的过程会有 Stop The World
(STW)的情况发生,即此时用户线程会停止工作,如果 STW 的时间过长,则应用的可用性、实时性等就下降的很厉害。
GC
主要解决如下3个问题:
- 如何找到垃圾?
- 如何回收垃圾?
- 何时回收垃圾?
1.1如何找到垃圾?
所谓垃圾,指的是不再被使用(引用)的对象。Java 的对象都是在堆(Heap)上创建的,我们这里默认也只讨论堆。那么现在问题就变为如何判定一个对象是否还有被引用,思路主要有如下两种:
- 引用计数法,即在对象被引用时加1,去除引用时减1,如果引用值为0,即表明该对象可回收了。
- 可达性分析法,即通过遍历已知的存活对象(GC Roots)的引用链来标记出所有存活对象
方法1简单粗暴效率高,但准确度不行,尤其是面对互相引用的垃圾对象时无能为力。
方法2是目前常用的方法,这里有一个关键是 GC Roots
,它是判定的源头,感兴趣的同学可以自己去研究下,这里就不展开讲了。
1.2 如何回收垃圾?
垃圾找到了,该怎么回收呢?看起来似乎是个很傻的问题。直接收起来扔掉不就好了?!对应到程序的操作,就是直接将这些对象占用的空间标记为空闲不就好了吗?那我们就来看一下这个基础的回收算法:标记-清除(Mark-Sweep)算法。
1.2.1 标记-清除 算法(Mark Sweep)
该算法很简单,使用通过可达性分析分析方法标记出垃圾,然后直接回收掉垃圾区域。它的一个显著问题是一段时间后,内存会出现大量碎片,导致虽然碎片总和很大,但无法满足一个大对象的内存申请,从而导致 OOM,而过多的内存碎片(需要类似链表的数据结构维护),也会导致标记和清除的操作成本高,效率低下,如下图所示:
1.2.2 复制算法(Copying)
为了解决上面算法的效率问题,有人提出了复制算法。它将可用内存一分为二,每次只用一块,当这一块内存不够用时,便触发 GC,将当前存活对象复制(Copy)到另一块上,以此往复。这种算法高效的原因在于分配内存时只需要将指针后移,不需要维护链表等。但它最大的问题是对内存的浪费,使用率只有 50%。
但这种算法在一种情况下会很高效:Java 对象的存活时间极短。据 IBM 研究,Java 对象高达 98% 是朝生夕死的,这也意味着每次 GC 可以回收大部分的内存,需要复制的数据量也很小,这样它的执行效率就会很高。
1.2.3 标记-整理算法(Mark Compact)
该算法解决了第1中算法的内存碎片问题,它会在回收阶段将所有内存做整理。但它的问题也在于增加了整理阶段,也就增加了 GC 的时间。
如下图所示:
1.2.4 分代收集算法(Generation Collection)
既然大部分 Java 对象是朝生夕死的,那么我们将内存按照 Java 生存时间分为 新生代(Young)
和 老年代(Old)
,前者存放短命僧,后者存放长寿佛,当然长寿佛也是由短命僧升级上来的。然后针对两者可以采用不同的回收算法,比如对于新生代
采用复制算法会比较高效,而对老年代
可以采用标记-清除或者标记-整理算法。这种算法也是最常用的。JVM Heap 分代后的划分一般如下所示,新生代一般会分为 Eden、Survivor0、Survivor1区,便于使用复制算法。
将内存分代后的 GC 过程一般类似下图所示:
- 对象一般都是先在
Eden
区创建 - 当
Eden
区满,触发 Young GC,此时将Eden
中还存活的对象复制到S0
中,并清空Eden
区后继续为新的对象分配内存 - 当
Eden
区再次满后,触发又一次的 Young GC,此时会将Eden
和S0
中存活的对象复制到S1
中,然后清空Eden
和S0
后继续为新的对象分配内存 - 每经过一次 Young GC,存活下来的对象都会将自己存活次数加1,当达到一定次数后,会随着一次 Young GC 晋升到
Old
区 Old
区也会在合适的时机进行自己的 GC
1.2.5 常见的垃圾收集器
前面我们讲了众多的垃圾收集算法,那么其具体的实现就是垃圾收集器,也是我们实际使用中会具体用到的。现代的垃圾收集机制基本都是分代收集算法,而 Young
与 Old
区分别有不同的垃圾收集器,简单总结如下图:
从上图我们可以看到 Young
与 Old
区有不同的垃圾收集器,实际使用时会搭配使用,也就是上图中两两连线的收集器是可以搭配使用的。这些垃圾收集器按照运行原理大概可以分为如下几类:
- Serial GC,串行,单线程的收集器,运行 GC 时需要停止所有的用户线程,且只有一个 GC 线程
- Parallel GC,并行,多线程的收集器,是 Serial 的多线程版,运行时也需要停止所有用户线程,但同时运行多个 GC 线程,所以效率高一些
- Concurrent GC,并发,多线程收集器,GC 分多阶段执行,部分阶段允许用户线程与 GC 线程同时运行,这也就是并发的意思,大家要和并行做一个区分。
- 其他
我们下面简单看一下他们的运行机制。
1.2.5.1 Serial GC
该类 Young区
的为 Serial GC
,Old区
的为Serial Old GC
。执行大致如下所示:
1.2.5.2 Parallel GC
该类Young 区
的有 ParNew
和 Parallel Scavenge
,Old 区
的有Parallel Old
。其运行机制如下,相比 Serial GC ,其最大特点在于 GC 线程是并行的,效率高很多:
1.2.5.3 Concurrent Mark-Sweep GC
该类目前只是针对 Old 区
,最常见就是CMS GC
,它的执行分为多个阶段,只有部分阶段需要停止用户进程,这里不详细介绍了,感兴趣可以去找相关文章来看,大体执行如下:
1.2.5.4 其他
目前最新的 GC 有G1GC
和ZGC
,其运行机制与上述均不相同,虽然他们也是分代收集算法,但会把 Heap 分成多个 region 来做处理,这里不展开讲。
参考资料
- Java Hotspot G1 GC的一些关键技术(https://mp.weixin.qq.com/s/4ufdCXCwO56WAJnzng_-ow)
- Understanding Java Garbage Collection(https://www.cubrid.org/blog/understanding-java-garbage-collection)
- 《深入理解Java虚拟机:JVM高级特性与最佳实践》
JVM&GC的更多相关文章
- 如何避免后台IO高负载造成的长时间JVM GC停顿(转)
译者著:其实本文的中心意思非常简单,没有耐心的读者建议直接拉到最后看结论部分,有兴趣的读者可以详细阅读一下. 原文发表于Linkedin Engineering,作者 Zhenyun Zhuang是L ...
- 【转载】Java性能优化之JVM GC(垃圾回收机制)
文章来源:https://zhuanlan.zhihu.com/p/25539690 Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我 ...
- JVM GC机制
垃圾收集主要是针对堆和方法区进行. 回收机制: 现在的JVM基本都使用分代回收机制,把堆中内存区域分为新生代,老年代. 新生代: Eden(80%) Survivor0(10%) Survivor1( ...
- 深入浅出 JVM GC(3)
# 前言 在 深入浅出 JVM GC(2) 中,我们介绍了一些 GC 算法,GC 名词,同时也留下了一个问题,就是每个 GC 收集器的具体作用.有哪些 GC 收集器呢? Serial 串行收集器(只适 ...
- 深入浅出 JVM GC(2)
# 前言 在 深入浅出 JVM GC(1) 中,限于上篇文章的篇幅,我们留下了一个问题 : 如何回收? 这篇文章将重点讲述这个问题. 在上篇文章中,我们也列出了一些大纲,今天我们就按照那个大纲来逐个讲 ...
- JVM 自带性能监测调优工具 (jstack、jstat)及 JVM GC 调优
1. jstack:占用最多资源(CPU 内存)的Java代码 https://www.cnblogs.com/chengJAVA/p/5821218.html https://blog.csdn.n ...
- 理解JVM GC
理解JVM GC对于我们把控Java应用有很大的帮助.下面我从运维角度,把网上的JVM相关的资料整理如下,以加深对JVM GC的理解.如有错误的地方,请看官指正. JVM内存使用分类 JVM的内存分区 ...
- Java性能优化之JVM GC(垃圾回收机制)
Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会在任何一种GC算法中发生.st ...
- JVM gc介绍
Java语言出来之前,大家都在拼命的写C或者C++的程序,而此时存在一个很大的矛盾,C++等语言创建对象要不断的去开辟空间,不用的时候有需要不断的去释放控件,既要写构造函数,又要写析构函数,很多时候都 ...
- 一夜搞懂 | JVM GC&内存分配
前言 本文已经收录到我的Github个人博客,欢迎大佬们光临寒舍: 我的GIthub博客 学习导图 一.为什么要学习GC&内存分配? 时代发展到现在,如今的内存动态分配与内存回收技术已经相当成 ...
随机推荐
- 【转】从phpMyAdmin批量导入Excel内容到MySQL(亲测非常简洁有效)
今天做项目遇到需要用phpMyAdmin批量导入Excel内容到MySQL数据库.分析了我的踏坑经历并且总结一最便捷的一套导入数据的方法,非常实用简洁: 1.修改Excel表的数据,使得Excel中的 ...
- Hadoop编程调用HDFS(PYTHON)
1.运行环境 开发工具:PyCharm Python 版本:3.5 Hadoop环境: Cloudera QuickStart 2.GITHUB地址 https://github.com/nbfujx ...
- 用C#编写ActiveX控件,开发浏览器控件,注册ActiveX 控件
用C#编写ActiveX控件,开发浏览器控件,注册ActiveX 控件用C#编写ActiveX控件 开发浏览器控件这是本控件开发完成后的一个简单应用.我们可以利用它以本地文件夹为单位来批量更新服务器的 ...
- angular项目引用第三方公共js文件
由于项目需要,领导要求在正在开发的angular项目中,引入公共js,以便进行统计计算. 于是便各种找度娘,网上有好多引用jquery插件的例子,于是便按照步骤对自身项目进行了改造,先记录一下: st ...
- 4 November in ss
Contest A. 输油管道问题 某石油公司计划建造一条由东向西的主输油管道.该管道要穿过一个有 \(n\) 口油井的油田.从每口油井都要有一条输油管道沿最短路经 (或南或北) 与主管道相连.如果给 ...
- [CSP-S模拟测试]:physics(二维前缀和+二分+剪枝)
题目传送门(内部题26) 输入格式 第一行有$3$个整数$n,m,q$.然后有$n$行,每行有一个长度为$m$的字符串,$+$表示正电粒子,$-$表示负电粒子.然后有$q$行,每行$2$个整数$x,y ...
- 两个图层一上一下div view
<view class="main"> <view class="user-info"> </view> <view ...
- oracle函数自治事务解决不能增改删的语句操作
CREATE OR REPLACE FUNCTION SEQ3 (v_bname in VARCHAR2) return NUMBER is pragma autonomous_transaction ...
- C#关于日期 月 天数 和一年有多少周及根据某年某周获取时间段的计算(转)
/// 当前月有多少天 /// </summary> /// <param name="y"></param> /// <param na ...
- selenuim,webdriver 基础3
代码要多敲 注释要清晰 哪怕很简单 对基础1和2 的补充 可以结合1和2来学习 from selenium import webdriver #生成浏览器对象 driver = webdriver.P ...