第三章 垃圾收集器与内存分配策略

GC三件事

  • 哪些内存需要回收
  • 何时回收
  • 怎么回收

主要考虑的是方法区

如何判断对象已死

1、引用计数:实现简单,教科书答案,java虚拟机没有采用

2、根搜索算法:

基本思路就是通过一系列名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。

3、java里面可以作为GCRoots的对象:

a.虚拟机栈(栈桢中的本地变量表)中的引用的对象

b.方法区中的类静态属性引用的对象

c.方法区中的常量引用的对象

d.本地方法栈中JNI的引用的对象

4、如何判断一个对象已死

  • 该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。
  • 加载该类的ClassLoader已经被回收。
  • 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该
    类的方法

5、垃圾收集算法

算法名称 英文名 描述 优点 缺点
标记-清除 Mark-Sweep 算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象 1、效率不高;2、内存碎片,效率不高
复制算法 Copying 将内存分为一块较大的Eden空间和两块较小的Survivor空间,8:1,内存利用率90% 解决了效率问题【适合新生代】 利用率低了
标记-整理 Mark-Compact 标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存 减少复制,减少空间浪费
分代收集算法 Generational Collection 根据对象存活周期的不同将内存划分为几块。一般为新生代和老生代,新生代采用复制算法,老生代采用标记-清除 或是 标记-整理

6、垃圾收集器

如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现
HotSpot虚拟机的垃圾收集器

名字 新\老 生代 原理 优点 缺点 备注
Serial收集器 复制算法;收集器是一个单线程的收集器;必须暂停其他所有的工作线程,直到它收集结束 简单而高效,少了线程交互开销 Stop The World Client模式下的虚拟机新生代默认选择
ParNew收集器 ParNew收集器其实就是Serial收集器的多线程版本 多线程 单CPU还不如Serial收集器 是许多运行在Server模式下的虚拟机中首选的新生代收集器,其中有一个与性能无关但很重要的原因是,除了Serial收集器外,目前只有它能与CMS收集器配合工作
Parallel Scavenge收集器 Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量(Throughput)。所谓吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间) 复制算法;并行
Serial Old收集器 使用“标记-整理”算法
Parallel Old收集器 Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法
CMS收集器(Concurrent Mark Sweep) CMS收集器是基于“标记—清除”算法实现的

并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状
态。

并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能
会交替执行),用户程序在继续运行,而垃圾收集程序运行于另一个CPU上。

7、理解GC日志

2017-03-24T11:18:49.803+0800: 311976.229: [GC (Allocation Failure) 2017-03-24T11:18:49.803+0800: 311976.229: [ParNew: 1428004K->26220K(1485504K), 0.0369712 secs] 3356779K->1955081K(5155520K), 0.0373455 secs] [Times: user=0.13 sys=0.00, real=0.04 secs]

2017-03-24T11:18:49.803+0800:【1】 311976.229:【2】 [GC【3】 (Allocation Failure【4】) 2017-03-24T11:18:49.803+0800: 311976.229: [ParNew:【5】 1428004K->26220K【6】 (1485504K【7】), 0.0369712 secs【8】] 3356779K->1955081K【9】(5155520K【10】), 0.0373455 secs【11】] [Times: user=0.13 sys=0.00, real=0.04 secs【12】]

详解:

  • 2017-03-24T11:18:49.803+0800【1】GC事件(GC event)开始的时间点
  • 311976.229:【2】GC时间的开始时间,相对于JVM的启动时间,单位是秒(Measured in seconds)
  • GC 【3】用来区分(distinguish)是 Minor GC 还是 Full GC 的标志(Flag). 这里的 GC 表明本次发生的是 Minor GC.
  • Allocation Failure 【4】引起垃圾回收的原因. 本次GC是因为年轻代中没有任何合适的区域能够存放需要分配的数据结构而触发的.
  • ParNew: 【5】使用的垃圾收集器的名字
  • 1428004K->26220K 【6】在本次垃圾收集之前和之后的年轻代内存使用情况(Usage)
  • 1485504K 【7】年轻代的总的大小(Total size).
  • 0.0369712 secs【8】该内存区域GC所占用的时间,单位是秒
  • 3356779K->1955081K 【9】在本次垃圾收集之前和之后整个堆内存的使用情况(Total used heap)
  • 5155520K 【10】总的可用的堆内存(Total available heap).
  • 0.0373455 secs【11】GC事件的持续时间(Duration),单位是秒
  • Times: user=0.13 sys=0.00, real=0.04 secs 【12】这里面的user、
    sys和real与Linux的time命令所输出的时间含义一致,分别代表用户态消耗的CPU时间、内核 态消耗的CPU事件和操作从开始到结束所经过的墙钟时间(Wall Clock Time)。CPU时间与
    墙钟时间的区别是,墙钟时间包括各种非运算的等待耗时.

8、内存分配与回收策略

  • 对象优先在Eden分配
package study3;

/**
 *
 * -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
 * @date 2017/03/24
 */
public class TestAllocation {
    public static void main(String[] args) {
        final int _1MB = 1024 * 1024;
        byte[] allocation1, allocation2, allocation3, allocation4;
        allocation1 = new byte[2 * _1MB];
        allocation2 = new byte[2 * _1MB];
        allocation3 = new byte[2 * _1MB];
        // 出现一次Minor GC
        allocation4 = new byte[4 * _1MB];
    }
}

[GC [ParNew: 8118K->473K(9216K), 0.0075132 secs] 8118K->473K(19456K), 0.0086882 secs] [Times: user=0.00 sys=0.01, real=0.01 secs] 
Heap
 par new generation   total 9216K, used 4981K [7f9a00000, 7fa400000, 7fa400000)
  eden space 8192K,  55% used [7f9a00000, 7f9e66db0, 7fa200000)
  from space 1024K,  46% used [7fa300000, 7fa3767f0, 7fa400000)
  to   space 1024K,   0% used [7fa200000, 7fa200000, 7fa300000)
 concurrent mark-sweep generation total 10240K, used 0K [7fa400000, 7fae00000, 7fae00000)
 concurrent-mark-sweep perm gen total 21248K, used 4898K [7fae00000, 7fc2c0000, 800000000)
  • 大对象直接进入老年代
  • 长期存活的对象将进入老年代
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容