JVM 内存结构和垃圾回收

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

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

  • Eden

小于阈值的新生对象区。

1.4.2 Old

1.5 元数据区

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

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

  • CCS(压缩类空间)

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

  • CodeCache

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 分带垃圾回收

  • Young 区采用复制算法,Old 采用标记清除或标记整理。对象在 Young 区分配,大部分对象生命周期非常短,采用复制算法效率非常高。Old 区存放对象生命周期长,垃圾较少。

  • 对象分配到 Egen 区(大对象直接进入 Old 区,大于 -XX:PretenureSizeThreshold),当 Eden 区域空间占用达到一定阈值时,触发 Minor GC,将被引用的对象分配到 Survivor 区域,没有被引用对象被回收,存活对象年龄标记为 1。

  • 经过一次 Minor GC,Eden 空闲,当 Eden 再次达到阈值,触发 Minor GC,Egen 区域的存活的对象和 From 区对象,被复制到 to 区,年龄加 1 。第二次发生多次,直到有对象年龄达到阈值(-XX:MaxTenuringThreshold,默认值为 15),则会晋升到老年代。-XX:TargetSurvivorRatio 存活对象比例,计算该比例下对象的平均年龄,取其和-XX:MaxTenuringThreshold的最小值,作为晋升年龄。

  • 老年代的 GC 称为 Major GC。

3.5 垃圾回收器

3.5.1 类型

  • 串行:SerialGC、SerialOldGC

  • 并行:Parallel ScanvengeGC、Parallel Old

  • 并发: CMS、G1

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 过程
  • 初始标记 Root,STW

  • 并发标记

  • 并发预清

  • 重新标记:STW

  • 并发清除

  • 并发重置

3.5.3.1.3 缺点
  • CPU 敏感

  • 浮动垃圾:并行标记时,应用线程进行内存分配。

  • 空间碎片

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 如何选择垃圾回收器

  • 优先调整堆的大小让服务器自己来选择。

  • 如果内存小于 100M,使用串行收集器。

  • 如果是单核并且对停顿时间没要求,选用串行垃圾回收器或让 JVM 自己选。

  • 如果允许停顿时间超过 1 秒,选用并行垃圾回收器或让 JVM 自己选。

  • 如果响应时间,并且不能超过 1 秒,选用并发垃圾回收器。

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 进行查看。

实战代码

参考资料

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容