JVM的GC策略
1 前言
GC(Garbage Collect)是jvm对于内存管理的核心功能,正是因为它才让Java程序员从内存释放的苦海中脱离出来,所以作为一个程序员都有必要去了解一下他的原理。
说一句题外话,我曾经被问到GC的具体实现,那个时候我就知道一些基本的思想,结果被人鄙视了。对于这个问题我到现在仍保留个人观点,就算java用了很久,如果不涉及到java程序的性能调优,GC其实也不用钻那么深。但是GC的思想中积累了很多的智慧,真是不得不去好好领略一下。苦于原来一直找不到一个比较系统的GC资料,我这里做一个相对系统一点的介绍,希望对后来人有帮助。
2 内存划分
说道GC,我们必须先要了解一下jvm的内存空间是如何划分的,本文只以Sun JDK为例,其划分为Permanent Generation(又称方法区、持久代)、Heap(堆)、Native Method Stack、JVM Method Stack、PC register。
Permanet Generation中是要加载类的相关信息,包括方法信息、静态变量等。如果超出指定大小,会抛出OutOfMemory的错误。
Heap,用于存对象实例和数值,分为New Generation和Old Generation。前者用户存储新生成的对象,后者用于存放多次GC后仍然存活的对象。如果超出指定大小,会抛出OutOfMemory的错误。
JVM Method Stack、PC register是随着线程创建的,他们只会占用操作系统内存或寄存器,由于线程私有,所以性能很高。如果超出指定大小,会抛出StackOverflowError的错误。
Native Method Stack在Sun JDK的实现中是和JVM Method Stack放在一起的。
3 内存分配
如果java要使用内存,第一步当然是要获取内存,这是由jvm进行分配的。上面说过了,新建对象都是在Heap的New Generation上的,而Heap又是所有线程共享的,可以想象必须要有锁机制才能保证安全。但是这当然会带来效率问题,所以这里有个优化,就是每个线程会分配一个TLAB(Thread Local Allocation Buffer),这个是线程独享的,当然给的空间也很小。默认是优先在TLAB上分配,所以为什么写小对象对java程序而言更合理。还有一种优化这里也说一下,就是jvm会根据实际运行情况进行分析,如果逃逸分析正好发现方法中的变量会被外部读取,那么就可以直接在Stack上分配,压根不用过Heap了。
4 GC算法
这里才是重头戏,看看具体GC的算法吧。其实没什么高深的内容,就是遇到的实际问题来找对应的解决办法。
4.1 引用计数法
简单的想一下,如果一个对象没有被任何人引用,那么他就要被回收。这个实现起来很简单,但是会有一个问题。如果有两个对象互相引用,但是没有任何其他对象引用他们,那么他们就会造成资源泄漏。所以实际使用时还是有些问题的,只能适合一些简单引用的场景。
4.2 跟踪收集法
就是把整个引用想象成一个允许有环路的树结构,但是根节点只有一个,然后从根节点出发去查看对象是否可达。但这个就是要程序暂停,来保证一次扫描的现场不变。
4.2.1 Copying
开辟另外一个内存空间,把扫描到可达的对象复制过去,然后把原内存空间全部清除即可。适用于存活对象较少的情况。
4.2.2 Mark-Sweep
把扫描到可达的对象都标记下来,然后把所有未标记的对象清除。但这个方法会引起内存碎片。适用于存活对象较多的情况。
4.2.3 Mark-Compact
在Mark-Sweep基础上,在把内存空间整理一下,让存储连续以消除内存碎片。
5 jvm实现
学了这么多基础知识,看看Sun JDK是怎么做的吧。
先搞清楚jvm到底要对什么进行GC。上面说的几种需要用内存的地方,Native Method Stack、JVM Method Stack、PC register是用的操作系统内存,用完就直接释放了,不需要我们多操心。Permanet Generation是加载类的相关信息,考虑到有动态加载,这个地方还是有可能需要GC的。Heap是对象生成和存活的土壤,这当然是GC的主要目标。
我们还是先解释两个名词,还记得上面说的New Generation和Old Generation吗?为什么要把Heap划分成这两类?原因就是他们所存的对象有完全不一样的特征,就是存活时间。因此我们自然想到要使用不一样GC策略。对于New Generation的GC叫做Minor GC,对于他们两个一起的GC叫做Full GC。再补充一个常识,就是New Generation通常不会太大,而Old Generation会比较大。所以一定要注意,Full GC的开销非常大,是要尽量避免的。
5.1 New Generation的GC策略
Serial GC。采用单线程方式,用Copying算法。到这里我们再来说说为什么New Generation会再次被划分成Eden Space和S0、S1,相信聪明的你一定已经想到Copying算法所需要的额外内存空间了吧,S0和S1又称为From Space和To Space。具体细节自己好好想想。
Parallel Scavenge。将内存空间分段来使用多线程,也是用Copying算法。
ParNew。比Parallel Scavenge多做了与Old Generation使用CMS GC一起发生时的特殊处理。
5.2 Old Generation的GC策略
Serial GC。当然也是单线程方式,但是实现是将Mark-Sweep和Mark-Compact结合了下,做了点改进。
Parallel Mark-Sweep、Parallel Mark-Compact。同样也是把Old Generation空间进行划分成regions,只是粒度更细了。为什么用这两个算法,不用我赘述了吧。
CMS(Concurrent Mark-Sweep) GC。我承认这个GC我真的没怎么看懂,目的是为了实现并发,结果就造成具体实现太麻烦了。有兴趣的朋友去看书吧,文末我说了是哪本书。这里有个地方可以说一下,就是算法使用的还是Mark-Sweep,对于内存碎片的问题,CMS提供了一个内存碎片的整理功能,会在执行几次Full GC以后执行一次。
6 如何使用
知道jvm怎么做的,那我们怎么用呢?这才是最实际的问题。其实每种GC方式都可以在启动时用参数指定,具体还是去看书。我提一下client和server模式。默认情况下是client模式,但是这个看机器配置自动选择,说了我估计你也记不住,用的话还是显示声明比较好。比较有意思的是这两种模式就可以认为用户所对应的不同场景,因此也会给出不一样的GC策略。具体如下表:
+----------------------------------------------------+
| | New Gen GC | Old Gen GC |
+--------+-------------------------------------------+
| client | Serial GC | Serial GC |
+--------+-------------------------------------------+
| server | Parallel Scavenge | Parallel Mark-Sweep GC|
+--------+-------------------------------------------+
JVM的GC策略的更多相关文章
- 【转】JVM 分代GC策略分析
我们以Sun HotSpot VM来进行分析,首先应该知道,如果我们没有指定任何GC策略的时候,JVM默认使用的GC策略.Java虚拟机是按照分代的方式来回收垃圾空间,我们应该知道,垃圾回收主要是针对 ...
- 关于JVM内存模型,GC策略以及类加载器的思考
JVM内存模型 Sun在2006年将Oracle JDK开源最终形成了Open JDK项目,两者在绝大部分的代码上都保持一致.JVM的内存模型是围绕着原子性(操作有且仅有一个结果).可见性(racin ...
- 深入学习重点分析java基础---第一章:深入理解jvm(java虚拟机) 第一节 java内存模型及gc策略
身为一个java程序员如果只会使用而不知原理称其为初级java程序员,知晓原理而升中级.融会贯通则为高级 作为有一个有技术追求的人,应当利用业余时间及零碎时间了解原理 近期在看深入理解java虚拟机 ...
- JVM内存模型以及HotSpot的GC策略
概述 想要进一步掌握Java语言,必须要深入了解一下Java程序的运行环境.本文会对JVM的内存模型.Java内存自动管理机制.以及Oracle官方虚拟机HotSpot在GC方面的实现策略进行大概的梳 ...
- JVM 分代GC策略分析
JVM 分代GC策略分析 我们以Sun HotSpot VM来进行分析,首先应该知道,如果我们没有指定任何GC策略的时候,JVM默认使用的GC策略.Java虚拟机是按照分代的方式来回收垃圾空间,我 ...
- 第一周JVM核心技术-工具与GC策略
一. JDK工具 1.1 内置命令行工具 工具 简介 jps/jinfo 查看java进程 jstat 查看JVM内部GC信息 jmap 查看JVM堆或类占用空间信息 jstack 查看线程信息 jc ...
- HBase的几种调优(GC策略,flush,compact,split)
一:GC的调优 1.jvm的内存 新生代:存活时间较短,一般存储刚生成的一些对象 老年代:存活时间较长,主要存储在应用程序中生命周期较长的对象 永久代:一般存储meta和class的信息 2.GC策略 ...
- 082 HBase的几种调优(GC策略,flush,compact,split)
一:GC的调优 1.jvm的内存 新生代:存活时间较短,一般存储刚生成的一些对象 老年代:存活时间较长,主要存储在应用程序中生命周期较长的对象 永久代:一般存储meta和class的信息 2.GC策略 ...
- Spark学习之路 (十四)SparkCore的调优之资源调优JVM的GC垃圾收集器
一.概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本 ...
随机推荐
- 如何防止网页被植入广告,内容被监控-HTTPS
前几天一朋友说访问网站页面底部怎么出现小广告了呢,内容有点不雅,朋友截图发给我,调侃我说怎么放这种广告,我一听纳闷,网站运行伊始,从来没有投放过任何广告,更别说不雅广告了. 最近还遇到一个问题就是,网 ...
- 【python3】爬取简书评论生成词云
一.起因: 昨天在简书上看到这么一篇文章<中国的父母,大都有毛病>,看完之后个人是比较认同作者的观点. 不过,翻了下评论,发现评论区争议颇大,基本两极化.好奇,想看看整体的评论是个什么样, ...
- 【CQOI2014】数三角形
题面 题解 考虑使用总数减去不合法的数量 首先将\(n, m\)都加上\(1\),将网格变成坐标系 总数即为\(\large\binom{n\times m}{3}\) 不合法的有三种情况: 三个点在 ...
- pandas:由列层次化索引延伸的一些思考
1. 删除列层次化索引 用pandas利用df.groupby.agg() 做聚合运算时遇到一个问题:产生了列方向上的两级索引,且需要删除一级索引.具体代码如下: # 每个uesr每天消费金额统计:和 ...
- Java 图片处理解决方案:ImageMagick 快速入门教程
文章首发于[博客园-陈树义],点击跳转到原文Java 图片处理解决方案:ImageMagick 快速入门教程. ImageMagick介绍 ImageMagick是一个免费的创建.编辑.合成图片的软件 ...
- SpringBoot实现监听redis key失效事件
需求: 处理订单过期自动取消,比如下单30分钟未支付自动更改订单状态 解决方案1: 可以利用redis天然的key自动过期机制,下单时将订单id写入redis,过期时间30分钟,30分钟后检查订单状态 ...
- Python 之Memcache中间件
一.引子 Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载,它通过在内存中缓存数据和减少读取数据库的次数,从而提高动态数据库驱动网站的速度.Memcache ...
- Python之元类详解
一.引子 元类属于Python面向对象编程的深层魔法,99%的人都不得要领,一些自以为搞明白元类的人其实也是自圆其说,点到为止,从队元类的控制上来看就破绽百出,逻辑混乱: 二.什么是元类 一切源自于一 ...
- 【SIKIA计划】_05_Unity5.3开发2D游戏笔记
一.界面基本操作 01.Project基本分类[Audios]音效[Material]材质[Prefabs]预制[Scenes]场景[Scripts]脚本[Sprites]精灵 02.Project丶 ...
- CHAPTER 7 Science in Islam 第7章 伊斯兰中的科学
CHAPTER 7 Science in Islam 第7章 伊斯兰中的科学 Galen did not live to see the decline of the Roman Empire, bu ...