性能测试全栈笔记:59.Jvm内存结构和垃圾回收
本期专题:性能测试全栈笔记:59.Jvm内存结构和垃圾回收
本期内容偏理论,较为枯燥,可自行选择学习
1.Java内存管理机制
- Java采用了自动管理内存的方式
- Java程序是运行在JVM之中的
- Java的跨平台的基于JVM的跨平台特性
- 内存的分配和对象的创建是在JVM中
- 用户可以通过一系列参数来配置JVM
2.Java运行时区域
3.Java内存结构
4.栈内存
- 线程私有
- 生命周期和线程相同
- 主要存放内容
- 基本数据类型(int,char,float,double…)
- 对象的引用,指向了对象在堆内存中起始地址
- 通过-Xss参数配置内存的分配和对象的创建是在JVM中
5.堆内存
- 堆内存是JVM中空间最大的区域
- 所有线程共享堆
- 所有的数组以及内存对象的实例都在此区域分配
- 堆内存大小通过参数进行配置
- -Xmx:最大堆内存
- -Xms:最小堆内存
- 堆内存 = 年轻代+老年代
- 年轻代 = Eden+Survivor
- Survivor = From Space(s0)+To Space(s1)
6.堆内存构成
- 堆内存构成:
- 新生代:包括三块区域,eden、from survivor(s0)、to survivor(s1)
- 老年代:old gen
7.永久代(PermGen)
- 永久代也叫(Method Area)
- 各线程共享,主方法区要存放类信息、常量、静态变量,如:public static int a = 10
- 垃圾回收行为比较少见
8.JVM结构总结
- 年轻代 = Eden+Survivor
- Survivor = From Space(s0) + To Space(s1)
- 年轻代 = Eden+From Space+To Space
- 堆内存 = 年轻代+老年代
- 堆内存=Eden+From Space+To Space+老年代
9.Java8新变化
- Java8从Jvm中移除了PermGen,使用Metaspace(元空间)来代替永久代
- Metaspace不存在Jvm中,而是存在本地内存中
- 配置元空间初始值和最大值参数:
-XX:MetaspaceSize=64m
-XX:MaxMetaspaceSize=64m
10.垃圾回收-GC
三个问题:
- 哪些内存需要回收?
- 什么时候回收?
- 如何回收?
11.YoungGC和FullGC
- 新生代引发的GC叫YoungGC
- 老年代引发的GC叫FullGC
- FullGC会引起整个Jvm的用户线程暂停,待垃圾回收完毕后,才继续运行
12.对象存活状态
- 确定对象“存活”还是“si去”
- 引用计数算法
- 根搜索算法(GC Roots)
- 引用的定义
- 如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表一个引用
13.永久代的垃圾回收
永久代回购“性价比”比较低
主要回收
废弃的常量
无用的类
- 类的所有实例都已经被回收
- 加载该类的ClassLoader已经被回收
- 该类的Class对象没有在任何地方被引用
14.堆垃圾回收算法
- 标记-清除算法
- 复制算法
- 标记-压缩算法
- 分代收集算法
15.标记-清除算法(Mark-Swap)
- 特点:
- 分为“标记”和“清除”两个阶段
- 标记完成后,统一回收
- 缺点:
- 效率,标记和清除过程效率都不高
- 空间,标记清除后会产生大量不连续的内存碎片
16.复制算法
- 特点:
- 内存分为相等的两块
- 当一块内存用完,将存活对象复制到另外一块中,
- 原内存一次性清理掉
- 复制时按照顺序分配内存,无内存碎片问题
- 新生代使用此算法
- 缺点:
- 将内存分为两半,利用率低
17.标记-压缩算法
- 特点:
- 先对存活对象进行标记
- 让所有存活对象向一边移动
- 清理掉存活对象边界外的所有内存
- 注:老年代使用此算法
18.分代收集算法
- 当代的商业虚拟机都采用“分代收集”
- 根据对象的存活周期的不同将内存划分成几块,一般Java堆分为新生代和老年代
- 新生代采用复制算法
- 老年代采用标记-压缩算法
19.垃圾收集器
- 垃圾收集器是内存回收算法的具体实现
- 没有完美的收集器
- Jvm不同的区域可以采用不同的垃圾收集器组合,主要有:
- Serial收集器(串行)
- ParNew收集器(并行)
- CMS收集器(并发)
- G1(时间优先)
20.Seria收集器
- 单线程收集器
- 用户线程全部停止(Stop the world)
- Client模式下,新生代默认收集器
- 优点:简单、高效
21.ParNew收集器
- 并行收集器,Serial收集器的多线程版本
- Server模式下Jvm默认的新生代收集器
- 默认开启的垃圾回收线程与cpu核数一致
22.CMS收集器
- 并发收集器(ConcurrentMarkSweep)
- 采用了标记-清除、标记-压缩算法
- 并发收集、低停顿
- 缺点:
- 消耗cpu
- 会产生内存碎片
- 浮动垃圾(Concurrent Mode Failure)
23.内存溢出
- 堆内存溢出
- 堆内存中存在大量对象,这些对象都有被引用,当所有对象占用空间达到堆内存的最大值,就会出现内存溢出
- OutOfMemory:Java heap space
- 永久代溢出
- 类的一些信息,如类名、访问修饰符、字段描述、方法描述等,所占空间大于永久代最大值,就会出现OutOfMemoryError:PermGen space
- 检测方法
- JDK/bin目录下有很多检测工具
- 图形界面:
- Jconsole
- Jvisualvm
- 命令行工具
- Jstat –gcutil pid 1000 100
- Jmap –histo pid | head -20
- Jmap –heap pid
- FullGC频率:建议单次FullGC时间<200ms
24.垃圾回收和CPU使用率
25.内存泄露和TPS
26.JVM常见参数
- -Xms2048m,初始堆大小,建议<物理内存的1/4,默认值为物理内存的1/64
- -Xmx2048m,最大堆大小,建议与-Xms保持一致,默认值为物理内存的1/4
- -Xmn512m,新生代大小,建议不超过堆内存的1/2
- -Xss256k,线程堆栈大小,建议256k
- -XX:PermSize=256m,永久代初始值,默认值为物理内存的1/64
- -XX:MaxPermSize=256m,永久代最大值,默认值为物理内存的1/4
- -XX:SurvivorRatio=8:年轻带中Eden区和Survivor区的比例,默认为8:1,即Eden(8),From Space(1),ToSpace(1)
- -XX:+UseConcMarkSweepGC:开启CMS垃圾回收器
27.G1垃圾回收
- G1全称是Garbage First Garbage Collector,在jdk1.7u4中开始支持。Java9中默认的垃圾收集器
- G1的设计原则就是简化性能优化的复杂性
本节详细内容请参考:深入理解Java虚拟机:JVM高级特性与最佳实践-第3版(pdf版)