JVM 内存结构和垃圾回收

2019-03-19  本文已影响0人  王龙江_3c83

1. JVM 内存结构

1228818-20180430152017807-1294956408.png

1.1 程序计数器

JVM 支持多线程同时执行,每个线程都有自己的程序计数器,线程正在执行 Java 代码,则存放正在执行的指令地址,如果正在执行 C 代码(本地方法),则为空。

1.2 虚拟机栈

线程私有,每个方法创建一个栈帧,用于存储局部变量表(this、参数列表、局部变量)、操作数栈(将下一个指令入栈,执行时出栈)、动态链接、方法出口等信息。方法从调用到执行完成对应栈帧的入栈到出栈,线程内串行。

1.3 本地方法栈

为虚拟机所使用的 C++ Native 方法服务。

1.4 堆

存放对象实例。

1.4.1 Young

同样大小,相同时间内,S0 和 S1 只有一个有数据,另一个为空。

小于阈值的新生对象区。

1.4.2 Old

1.5 元数据区

存放被虚拟机加载的类信息,包括常量、静态变量、即时编译器编译后代码等。

存放 Class、Package、Method、Field、字节码、常量池、符号引用。

堆中对象都有一个指向自己 Class 对象的指针,每个 64 位指针长度为 64 位,如果使用 32 位指针,Class 文件存放于 CCS 中。

JIT 即时编译后的代码和 JVM 执行的 JNI Native 代码。如果使用 -Xint 解释执行,则不会生成 CodeCache。

1.6.1 运行时常量池

方法区的一部分,存放类加载后生成的字面量和符号引用。

1.7 常用参数

参数 解释
-Xint 解释执行,运行时将 class 翻译成机器码。
-Xcomp 编译执行,第一次使用时进行编译,保存在 JVM 中。
-Xmixed 以方法为单位,将多次调用的代码翻译成机器码。
参数 解释
-Xms=-XX:InitialHeapSize 最小堆内存大小
-Xmx=-XX:MaxHeapSize 最大堆内存大小
-XX:NewSize -XX:MaxNewSize 最小/最大新生代大小
-XX:NewRatio 新生代(eden+s*s)和老年代的比值。
-XX:SurvivorRatio 两个 Survivor 区和 eden 的比值
-XX:MetaspaceSize/MaxMetaspaceSize 元数据区大小。
-XX:+UseCompressedClassPointers 使用压缩类指针
-XX:+UseCompressedClassSpaceSize 使用压缩类指针
-XX:InitialCodeCacheSize/ReservedCodeCacheSize CodeCache 区初始(最大)大小
-Xss=-XX:ThreadStackSize 设置每个线程的堆栈大小。

3. GC

3.1 垃圾判断算法

3.1.1 引用计数

3.1.2 可达性分析

选定活动对象(类加载器、Thread、虚拟机栈的本地变量表和本地方法栈作的变量、静态成员和常量)作为一个 GC Roots,然后跟踪引用链条。如果一个对象和 GC Roots 间不可达,即可认为是可回收对象。

3.2 性能指标

术语 解释
最长停顿时间 垃圾收集器做垃圾回收时中断应用执行的时间的最大值。-XX:MaxGCPauseMills最大停顿时间。
吞吐量 花在垃圾收集时间和花在应用时间的占比 -XX:GCTimeRatio,垃圾收集时间占比:1/1+n

3.3 垃圾收集算法

算法 解释 优点 缺点
复制算法 将堆内存按照容量分成大小相同的两块,每次只使用其中一块。当一块的内存用完时,将存活者的数据复制到另一块,然后将使用过的内存空间清除掉。 简单高效 空间利用率低。
标记清除算法 首先标识出所有需要回收的对象,然后统一回收。 导致内存碎化,标记和清除效率不高。
标记-整理算法 为了避免内存碎片化,在清理过程将对象移动。 没有内存碎片 整理内存耗时。

3.4 分带垃圾回收

3.5 垃圾回收器

3.5.1 类型

3.5.2 参数

参数 区域 线程 算法
-XX:+UseSerialGC 新生代 单线程 复制算法
-XX:+UseSerialOldGC 老年代 单线程 标记整理
-XX:+UseParallerGC 新生代 多线程 复制算法
-XX:+UseParallerOldGC 老年代 多线程 标记整理
-XX:+UseConcMarkSweepGC 老年代 多线程 标记清除
-XX:+UseParNewGC 新生代 多线程 标记整理
-XX:+UseG1GC 老年代和新生代 多线程 标记整理

3.5.1 串行收集器

3.5.2 并行收集器(Server 端默认)

3.5.2.1 使用场景

吞吐量优先:多垃圾收集线程并行工作,此时用户线程处于等待状态。适合科学计算、后台处理等弱交互场景。

3.5.2.2 参数

参数 解释
-XX:+UseParallerGC 对新生代使用并行垃圾回收器,对老年代使用 Ps MarkSweep(类似于串行垃圾回收器)。
-XX:+UseParallerOldGC 对老年代使用并行收集器。
-XX:ParallelGCThreads 并行的垃圾回收线程数,默认小于 8 核,线程数等于核数;大于 8核,等于 5/8 * 核数。
-XX:MaxGCPauseMills 最大停顿时间。
-XX:GCTimeRatio 垃圾收集时间占比:1/(1+n)
-Xmx 优先满足最大停顿时间和吞吐量,如果堆大小不能满足需求。
-XX:YoungGenerationSizeIncrement
-XX:TenuredGenerationSizeIncrement

3.5.3 并发收集器(响应时间优先)

垃圾回收线程和用户线程同时执行(但不一定是并行,可能交替执行),垃圾回收线程在执行的时候不会停顿用户程序的运行。适合对响应时间有要求(低于 1秒 )的场景,比如 Web。

3.5.3.1 CMS

3.5.3.1.1 参数
参数 解释
-XX:+UseConcMarkSweepGC 对老年代使用 CMS 垃圾回收算法。
-XX:+UseParNewGC 对新生代使用 ParNew 垃圾回收算法。
-XX:ConcGCThreads 并发的 GC 线程数。
-XX:+UseCMSCompactAtFullCollection FullGC 之后做压缩
-XX:CMSFullGCBeforeCompaction 多少次 FullGC 之后做压缩。
-XX:CMSInitiatingOccupancyFraction Old 占多大比例触发 FullGC
-XX:+UseCMSInitiatingOccupancyOnly Old 占多大比例触发 FullGC,是否动态可调。
-XX:+CMSScavengeBeforeRemark Full GC 之前做 YGC
-XX:+CMSClassUnloadingEnabled 启动回收 Perm 区。
3.5.3.1.2 过程
3.5.3.1.3 缺点

3.5.3.2 G1

3.5.3.2.1 参数
参数 解释
-XX:+UseG1GC 对老年代和新生代使用 G1 垃圾回收算法。
-XX:+InitiatingHeapOccupancyPercent 堆占有率达到这个值时,触发 global concurrent marking,默认 45%。
-XX:+G1HeapWastePercent 堆占有率达到这个值时,触发 global concurrent marking,默认 45%。

大内存(6GB)低停顿时间(0.5 s)小,新生代和老年代。

3.5.3.2.2 YoungGC

同上,大对象(大于 REGION 大小的 50%,进入 H 区)。

3.5.3.2.3 MixedGC

3.5.4 常用的收集器组合

新生代 老年代 说明
Serial Serial Old
Serial CMS CMS 退化 Serial Old
ParNew CMS CMS 对 Old 区进行垃圾回收,启用它时默认对 Young 区使用 ParNew GC。
ParNew Serial Old
Parallel Scavenge Serial Old
Parallel Scavenge Parallel Old
G1 G1

3.5.5 如何选择垃圾回收器

4. 内存监控

4.1 查看 Java 默认参数

参数 解释
java -XX:+PrintFlagsFinal -version 查看 JVM 参数。
java -XX:+PrintCommandLineFlags -version 查看 JVM 默认垃圾回收器。

4.2 查看 JVM 运行时参数

参数 解释
jstat 查看 JVM 统计信息,包括类装载、垃圾回收和 JIT 编译信息。
jstat -gc 查看 JVM 内存对分配和使用状况,GC 的次数和时间。
jstat -class 查看 JVM 类装载信息。
jstat -compiler 查看 JVM 编译信息。
jinfo -flag <name> <pid> 查看正在运行的 JVM 的参数值。
jinfo -flag <pid> Non-deafault VM flags,查看被修改的 JVM 的参数值。
jps 打印 java 进程号和进程名。
jps -v 打印 java 进程的详细信息。
jstack jstack 线程状态,结合 top -H -p <pid> 查看线程。
jmap -dump:format=b,file=heap.hprof <pid> 导出内存映像文件,使用 mat 进行查看。

实战代码

参考资料

上一篇下一篇

猜你喜欢

热点阅读