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|
 +--------+-------------------------------------------+

7 补充

最后,我说说S0和S1的作用吧,也顺便看看你想的对不对,其实我一开始也想错了。还记得对象从New Generation到Old Generation的条件吗?如果说几次GC都能存活下来才能过去,那计数会不会比较麻烦?New Generation中存在的所有对象都是放在Eden Space中的,S0和S1是存放上一次GC存活下来的对象,那么每次Minor GC就会知道Eden Space在GC后还有哪些活着的,与上一次S0或S1保存的结果比较一下是不是就知道了这个对象是不是在两次GC中都存活下来了,比较完就可以把一个Sx的信息清掉,再存放到另外一个Sx中。下次GC继续做这个比较。

本文转自passover 51CTO博客,原文链接:http://blog.51cto.com/passover/428441,如需转载请自行联系原作者

浅谈JVM的GC策略相关推荐

  1. 浅谈JVM(六):方法调用过程

    上一篇: 浅谈JVM(一):Class文件解析 浅谈JVM(二):类加载机制 浅谈JVM(三):类加载器和双亲委派 浅谈JVM(四):运行时数据区 浅谈JVM(五):虚拟机栈帧结构 6.方法调用过程 ...

  2. 浅谈信息学竞赛考场策略及程序测试

    浅谈信息学竞赛考场策略及程序测试 主题 本文作者是江苏省常州高级中学吴翼同学发布的信息学竞赛江苏省论文.内容对于大家备考十分有帮助,特分享给同学们,希望在中秋假期给大家的学习增加一点动力! 考场策略和 ...

  3. 盲校计算机教学策略,浅谈盲校计算机教学策略.doc

    浅谈盲校计算机教学策略 浅谈盲校计算机教学策略 摘要:近年来,随着信息技术的飞速发展,计算机几乎随处可见.然而,因为盲生存在着视力障碍,获取外界知识的方式非常有限,再加上他们心理上存在着自卑感,不愿与 ...

  4. 浅谈 JVM 内存结构及 GC 机制

    前言 JAVA GC(Garbage Collection,垃圾回收)机制是区别C++的一个重要特征,C++需要开发者自己实现垃圾回收的逻辑,而JAVA开发者则只需要专注于业务开发,因为垃圾回收这件繁 ...

  5. 浅谈JVM(面试常考)

    JVM 简介 1. JVM 内存区域划分 1.1 程序计数器(线程私有) 1.2 Java 虚拟机栈(线程私有) 1.3 本地方法栈(线程私有) 1.4 堆(线程共享) 1.5 方法区(线程共享) 2 ...

  6. 浅谈JVM的实现与垃圾回收机制

    Java被称为是一个人类可读的编程语言,其主要特点是基于类和面向对象,Java的开源版本被称为OpenJDK.Java编程环境由两个部分组成:Java语言和运行环境,运行环境也称为Java虚拟机(JV ...

  7. java gc 可以对方法区进行回收_浅谈 Java 之 GC

    阅读本文假设你对java内存模型已有一些了解. 1.Java虚拟机中哪些内存需要回收? 先来看看jvm内存模型,如下图 线程隔离的区域随线程而生,随线程而灭:程序计数器可保存着虚拟机字节码指令的地址( ...

  8. java gc 次数_浅谈如何减少GC的次数

    GC会stop the world.会暂停程序的执行,带来延迟的代价.所以在开发中,我们不希望GC的次数过多. 本文将讨论如何在开发中改善各种细节,从而减少GC的次数. (1)对象不用时最好显式置为 ...

  9. jvm内存结构_浅谈JVM内存结构

    JVM 可以分为 5 个部分,分别是: 类加载器(Class Loader):加载字节码文件到内存. 运行时数据区(Runtime Data Area):JVM 核心内存空间结构模型. 执行引擎(Ex ...

最新文章

  1. Spring Boot整合Mybatis-Plus 增删改查+ 分页基本使用完整示例
  2. NeurIPS 2019 | 用于弱监督图像语义分割的新型损失函数
  3. Comet:基于 HTTP 长连接的“服务器推”技术解析
  4. 中国人工智能学会通讯——基于视频的行为识别技术 1.7 视频的深度分段网络...
  5. Quaruts II 增量编译
  6. 在Spring Boot中实现相关ID(用于SOA /微服务中的分布式跟踪)
  7. Hystrix面试 - 基于 timeout 机制为服务接口调用超时提供安全保护
  8. 小米这两款手机沦为“难兄难弟”,再降价也清不了库存
  9. Video Analysis 相关领域解读之Video Captioning(视频to文字描述)
  10. stderr 用法 linux,linux – 如何在使用“tee”时使用管道将stderr写入文件?
  11. 【mysql】关于IO/内存方面的一些优化
  12. 无法打开网上邻居计算机,win7网上邻居在哪 无法访问怎么办【图文】
  13. mount挂载不上,不提示任何信息
  14. HTML,CSS中的复合写法总结
  15. 【JavaWeb】JQuery实现广告显示和隐藏动画效果
  16. 安卓游戏应用如何在linux上流畅运行
  17. 如何练胸肌(完整篇)
  18. mysql columns_MySQL的show columns命令
  19. python web微信应用(二) webwx 模块源码
  20. (0101)iOS开发之iPad模拟器如何实现分屏模式调试

热门文章

  1. 使用组策略配置Windows 7的高级防火墙
  2. 唐山一个葬礼上的豪华车队
  3. CowNew开源团队4月14日聚会
  4. email util demo
  5. [cocos2d-x]图层的旋转缩放效果
  6. quick check
  7. 如何解决XML文件中的警告提示“No grammar constraints (DTD or XML Schema) referenced in the document.”...
  8. jax-rs的客户端完整实例
  9. Dsure-HTML5网站前端开发框架,网页设计师福利
  10. myeclipse6.0下载及注冊码