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策略的更多相关文章

  1. 【转】JVM 分代GC策略分析

    我们以Sun HotSpot VM来进行分析,首先应该知道,如果我们没有指定任何GC策略的时候,JVM默认使用的GC策略.Java虚拟机是按照分代的方式来回收垃圾空间,我们应该知道,垃圾回收主要是针对 ...

  2. 关于JVM内存模型,GC策略以及类加载器的思考

    JVM内存模型 Sun在2006年将Oracle JDK开源最终形成了Open JDK项目,两者在绝大部分的代码上都保持一致.JVM的内存模型是围绕着原子性(操作有且仅有一个结果).可见性(racin ...

  3. 深入学习重点分析java基础---第一章:深入理解jvm(java虚拟机) 第一节 java内存模型及gc策略

    身为一个java程序员如果只会使用而不知原理称其为初级java程序员,知晓原理而升中级.融会贯通则为高级 作为有一个有技术追求的人,应当利用业余时间及零碎时间了解原理 近期在看深入理解java虚拟机 ...

  4. JVM内存模型以及HotSpot的GC策略

    概述 想要进一步掌握Java语言,必须要深入了解一下Java程序的运行环境.本文会对JVM的内存模型.Java内存自动管理机制.以及Oracle官方虚拟机HotSpot在GC方面的实现策略进行大概的梳 ...

  5. JVM 分代GC策略分析

    JVM 分代GC策略分析   我们以Sun HotSpot VM来进行分析,首先应该知道,如果我们没有指定任何GC策略的时候,JVM默认使用的GC策略.Java虚拟机是按照分代的方式来回收垃圾空间,我 ...

  6. 第一周JVM核心技术-工具与GC策略

    一. JDK工具 1.1 内置命令行工具 工具 简介 jps/jinfo 查看java进程 jstat 查看JVM内部GC信息 jmap 查看JVM堆或类占用空间信息 jstack 查看线程信息 jc ...

  7. HBase的几种调优(GC策略,flush,compact,split)

    一:GC的调优 1.jvm的内存 新生代:存活时间较短,一般存储刚生成的一些对象 老年代:存活时间较长,主要存储在应用程序中生命周期较长的对象 永久代:一般存储meta和class的信息 2.GC策略 ...

  8. 082 HBase的几种调优(GC策略,flush,compact,split)

    一:GC的调优 1.jvm的内存 新生代:存活时间较短,一般存储刚生成的一些对象 老年代:存活时间较长,主要存储在应用程序中生命周期较长的对象 永久代:一般存储meta和class的信息 2.GC策略 ...

  9. Spark学习之路 (十四)SparkCore的调优之资源调优JVM的GC垃圾收集器

    一.概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本 ...

随机推荐

  1. TI DSP 6657 SRIO 简介

    目录 TI DSP 6657 SRIO 简介 SRIO 协议介绍 RapidIO 基础 TI DSP 6657 SRIO 简介 SRIO 协议介绍 TI 的 KeyStone 系列设备中实现了 Rap ...

  2. 菜鸟vimer成长记——第2.3章、insert模式

    大部分的Vim 命令都在非插入模式中执行,不过有些功能在插入模式中会更好实现些. 如果没有输入当前文件不存在的新文本的需求时,建议通过其他模式来操作完成. 目的 掌握inser模式下常用操作的语法和概 ...

  3. Security Permissions Caching

    Security Permissions Caching Security permission caching is implemented in Security Adapters - class ...

  4. ncl 函数源码 gc_inout

    转自气象家园论坛 经过不懈努力,终于找到了gc_inout函数的源代码,原来在这个文件里面!一颗赛艇 位置:/ncl_ncarg-6.5.0-src/ni/src/lib/nfpfort/sg_too ...

  5. centos7搭建ANT+jmeter+jenkins接口测试自动化环境

    一.环境准备 因为用到了jmeter和apache-tomcat,centos7必须要有java环境,所以配置jdk和apache-tomcat什么的,就不多说了,自行操作 帮你们偷懒: ant下载地 ...

  6. lua字符串类型

    Lua中字符串结构体的定义是: typedef union TString { L_Umaxalign dummy; /* ensures maximum alignment for strings ...

  7. 小冷-wireshark的标志位的值是啥

    小冷系列之 wireshark的标志位的值是啥,在用wireshark抓包时,发现Flags = 0x002(SYN),很好奇0x002是什么意思. 好不好先上图: 上图是一个三次握手第一次的标志位, ...

  8. CentOS7的安装与配置

    Linux系统以前接触的不多,主要是公司的网站部署在了一台安装了Ubuntu系统的机器上.是典型的LAMP架构的产物,因为偶而需要更新网站内容及需要定期备份.所以学习了一些Ubuntu & A ...

  9. Mysql Order By注入总结

    何为order by 注入 本文讨论的内容指可控制的位置在order by子句后,如下order参数可控"select * from goods order by $_GET['order' ...

  10. python json模块使用详情

    python其他知识目录 #json.数据交换用到json文件.json是特殊的字符串.访问网站,返回的就是json 1.json简介: 定义:JSON(JavaScript Object Notat ...