美文网首页
第三章 垃圾收集器与内存分配策略

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

作者: 骊骅 | 来源:发表于2017-03-24 17:47 被阅读58次

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)
  • 大对象直接进入老年代
  • 长期存活的对象将进入老年代

相关文章

网友评论

      本文标题:第三章 垃圾收集器与内存分配策略

      本文链接:https://www.haomeiwen.com/subject/huvfottx.html