<深入理解Java虚拟机>阅读笔记

Table of Contents

本文为周志明的<<深入理解Java虚拟机>>的读书笔记.

第2章:Java内存区域与内存溢出异常

本章主要讲了JVM的内存区域及可能出现的内存溢出问题.

内存区域划分

  1. 程序计数器. 线程私有区域(即每个线程都有). 记录当前线程指向的字节码地址. 如果执行的是Native方法,则为空.
  2. 虚拟机栈(VM Stack). 线程私有区域, 用于存储每个线程的函数执行过程中的栈帧. 可以存放基本数据类型,对象引用和returnAddress类型. 栈帧所需的空间大小在编译期间就是确定好的.
  3. 本地方法栈. 线程私有区域, 服务对Native方法的调用.
  4. 堆. 线程共享区域, 用于对象创建.
  5. 方法区. 线程共享区域. 存放被JVM加载的类信息,常量,静态变量等.

HotSpot虚拟机

Sun JDK和OpenJDK上使用的虚拟机.

  1. 使用new创建普通对象. 流程:
    1. 检查方法区的常量池中, 判断该类是否被加载,解析和初始化. 没有则执行相应的类加载过程.
    2. 从堆上分配一块内存给新实例.并初始化为零.
    3. 更新对象头信息.
  2. 对象组成. 包括三部分: 对象头, 实例数据, 填充.
    1. 对象头: 由 "Mark World" 和 "类型指针" 组成. Mark World包含了大部分的运行时数据:哈希码,GC年龄,锁…. 类型指针主要指向类元数据.

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

判断对象是否要回收的方法

  1. 引用技术算法. 主要思想就是对象的引用计数如果不为0则不回收对象. 可能出现的问题: 两个无用对象互相引用导致永远不会被回收.
  2. 可达性分析算法. 主要思想: 将一些对象设置为root,每次GC都从root作为起点向下搜索. 如果有对象Root不可达,那么就可以被回收. 可作为Root的有如下几种对象:
    • 栈帧中引用的对象
    • 方法区静态成员变量引用的对象.
    • 方法区常量引用的对象.
    • Native方法区中引用的对象.

引用类型

  1. 强引用. 被强引用的对象永远不会被回收.
  2. 软引用. 在内存不足时会对这些对象进行回收.回收完还不够会抛溢出异常.
  3. 弱引用. 下一次GC会被回收.
  4. 虚引用.

GC的两步论

GC过程中会检查被回收是否需要执行finalize()方法, 如果需要则执行该对象的该方法.(当一个类覆写了该方法并且从未被调用过时, 被调用,该方法只会被调用一次). 所以可以在该方法中拯救自己不被回收.

垃圾收集算法

  思想 优点 缺点
标记-清除算法 先标记要回收对象, 然后统一回收   效率低,容易产生碎片
复制算法 将新生代按比例分为Eden和Survivor区域, 回收时将存活对象复制到S区域,然后一次性清理Eden 分配只移动指针,高效 内存利用率降低
标记-整理算法 将老年代内存先标记,然后整体移动到内存的一端,然后回收端外的区域    

注:HotSpot虚拟机的复制算法比例为8:1, 所以Eden占内存区域的80%, 两个Survivor分别占据10%. 并且需要老年代做内存担保, 然suivivor无法容纳eden时,直接复制到老年代.

HotSpot算法实现

  1. HS使用OopMap来存放那些地方存放内存引用.
  2. Safe point机制来主要告知线程要进行GC.使其执行到安全点等待GC.
  3. Safe Region机制保证不响应Safe point的线程(sleep或block)可以安全GC.

HotSpot垃圾收集器

  思想 优点 缺点
Serial 单线程收集器,Stop The World 简单高效 停顿时间过长
ParNew 多线程收集器, STW 单线程效果不比Serial好
Parallel Scanvenge 关注吞吐量, 可以自动调整Eden大小. 使用复制算法 保证吞吐量  
Serial Old Serial的老年代版本 标记-整理算法  
Parallel Old Parallel Scanvenge的老年代版本 标记-整理算法  
CMS 初始标记(STW)->并发标记->重新标记(STW)->并发清除 最短停顿时间, 标记-清除算法 CPU敏感, 失败产生Full GC, 碎片导致Full GC
G1 将堆划为region,然后按优先级分次收集.    

内存分配策略

  1. 对象优先在Eden上分配, 内存不足触发 Minor GC.
  2. 大对象直接进入老年代.
  3. 长期存活的对象进入老年代. 对象在Eden出生时被赋予年龄, 随着年龄增大到一定值, 放入老年代.
  4. 动态年龄判定. Survivor空间中相同年龄对象大小超过S区域的一半,放入老年代.

附录

JVM参数

   
­XX:+HeapDumpOnOutOfMemoryError 内存溢出时dump当前内存堆
­Xss 设置栈内存容量
­XX:PermSize -XX:MaxPermSize 方法区大小
­Xmx 堆最大值
­XX:MaxDirectMemorySize 直接内存最大值
­XX:ParallelGCThreads 参与垃圾回收的线程数
­XX:MaxGCPauseMillis 最大垃圾收集停顿时间
­XX:GCTimeRatio 吞吐量大小
­XX:+PrintGCDetails 打印GC日志

Created At <2017-03-22 Wed> by Luis Xu. Email: xuzhengchaojob@gmail.com