-
判断对象的存活
- 引用计数法
1> 优点:快,方便,实现简单
2> 缺点:相互引用存在问题 - 可达性分析
1> 在java,可作为GC Roots的对象包括:
a, 方法区:类静态属性引用的对象
b, 方法区:常量引用的对象
c, 虚拟机栈(本地变量表)中引用的对象
d, 本地方法栈JNI(Native方法)中引用的对象
- 引用计数法
-
各种引用
- 强引用
1> Object o = new Object() - 软引用(SoftReference)
1> 一些有用但是并非必需,用软引用关联的对象,系统将要发生OOM之前这些对象就会被回收
2> User u = new User(); SoftReference<User> SoftReference = new SoftReference(u); u = null; //OOM
3> 用在内存资源紧张的情况下 - 弱引用(WeakReference)
1> 一些有用(有用的程度比软引用更低)但是并非必需,用弱引用关联的对象,只能生存到下次垃圾回收之前,GC发生时,不管内存是否足够都会被回收
2> User u = new User(); WeakReference<User> WeakReference = new WeakReference(u); u = null; System.gc()
3> 用在内存资源紧张的情况下
4> WeakHashMap就是使用了弱引用 - 虚引用(PhantomReference)
1> 幽灵有用,最弱,被垃圾回收的时候收到一个通知
- 强引用
-
垃圾回收算法
-
标记-清除算法(Mark-Sweep)
1> 会产生碎片,造成资源浪费 -
复制算法(Coping)
1> 浪费空间,总会有一半空间无法使用
2> 会移动数据,耗时 -
标记-整理算法(Mark-Compact)
1> 会移动数据,耗时 -
java虚拟机把算法都使用上,分代收集
1> 对象的生命周期不同,90%以上的对象朝生夕死
2> 新生代:刚new的对象,采用复制算法,Minor GCa, Eden 1个 b, Survivor 2个 c, 空间分配比例8(Eden):1(Survivor0):1(Survivor1)
3> 老年代:对象存活超过一定时间(GC次数)的对象,标记-整理或标记清除,Full GC。调优是希望尽可能少的FULL GC
4> 新生代经过一定次数的垃圾回收后依然未被回收的对象,会被移动到老年代区域,默认次数15
-
-
垃圾回收器列表
-
Serial 新生代 复制算法 单线程
-
ParNew 新生代 复制算法 并行的多线程
-
Parallel Scavenge 新生代 复制算法 并行的多线程
-
Serial Old 老年代 标记整理 单线程
-
Parallel Old 老年代 标记整理 并行的多线程收集器
-
CMS 老年代 标记清除 并行与并发收集器
分代收集.png -
G1(jdk7) 跨老年代和新生代 标记整理 + 化整为零 并行与并发收集器
-
垃圾收集的并行和并发
1> 并行:垃圾收集的多线程的同时进行
2> 并发:垃圾收集的多线程和应用的多线程同时进行 -
查看垃圾回收器:java -XX:+PrintCommandLineFlags -version
-
特点
1> Serial/Serial Old 最古老的,单线程,独占式,成熟,适用于单CPUa, -XX:UseSerailGC 新生代和老年代都用串行收集器 b, -XX:UseParNewGC 新生代使用ParNew,老年代使用Serial Old c, -XX:UseParallelGC 新生代使用ParallelGC,老年代使用Serial Old
2> ParNew和Serial基本没区别,唯一区别:多线程,适用于多CPU,停顿时间比Serial少
a, -XX:UseParNewGC 新生代使用ParNew,老年代使用Serial Old
-
3> Parallel Scavenge(ParallelGC)/Parallel Old 关注吞吐量
a, 停顿时间短的适合用户交互的程序(桌面应用),提高用户体验。
b, 关注吞吐量,适用于后台计算任务.
c, -XX:MaxGCPauseMills 控制最大停顿时间
d, -XX:GCTimeRatio 允许的GC时间占总时间的比率,吞吐量的导数,整数 允许的GC时间 比如19 1/1+19 = 5%
e, -XX:+UseAdaptiveSizePolicy 自适应的调整策略
d, -XX:+UsePrallerOldGC: 新生代ParallelGC,老年代 Parallel Old
4> CMS(Concurrent Mark Sweep) 关注最短停顿时间,标记清除
a, CMS运行的过程
(1) 初始标记:时间短暂,GC-Roots能直接关联的标记
(2) 并发标记:和用户的应用程序同时进行
(3) 重新标记:时间短暂
(4) 并发清除:和用户的应用程序同时进行
b, -XX:UseConcMarkSweepGC 表示老年代的用CMS,新生代使用ParNew
c, 浮动垃圾:用户的线程还在运行,需要给用户线程留下运行内存空间。
d, -XX:CMSInitialOccupyFraction当老年代的空间超过这个值时启动收集,默认68%(jdk6) -> 92%(jdk7以后)。
e, 不够时,产生错误:Concurrent Mode Failure,启动Serial Old收集器
f, -XX:UseCMSCompactAtFullCollection 需要Full GC的时候开启内存碎片的整理,无法并发,默认开启
g, -XX:CMSFullGCsBeforeCompaction 设置多少次不压缩的FullGC后来一次要压缩的,默认为0
垃圾回收器工作示意图.png
5> G1(Garbage First)
a, jdk7才正式引入,到jdk9默认是收集器。采用分区回收的思维,基本不牺牲吞吐量的前提下完成低停顿的内存回收;可以预测的提顿是其最大的优势
b, 面向服务端应用的垃圾回收器,目标取代CMS
c, 整体回收算法是标记整理,局部回收算法是复制算法
d, 设置参数 -XX:+UseG1GC
e, 并行和并发,分代收集,空间整合,没有空间碎片,可预测的停顿
f, G1收集运行
(1) 初始标记:时间短暂,GC-Roots能直接关联的标记,产生一个全局停顿,都会有一个新生代的GC
(2) 根区域扫描:扫描Survivor区可以直接到达老年代的区域
(3) 并发标记阶段
(4) 重新标记
(5) 独占清理
(6) 并发清理
g, G1收集的几个阶段
(1)新生代GC
(2)并发标记周期
(3)混合收集
(4)可能的FullGC
h, -XX:MaxGCPauseMillis 指定目标的最大停顿时间,G1尝试调整新生代和老年代的比例,堆大小,晋升年龄
i, -XX:ParallerGCThreads GC的工作线程数量
G1垃圾回收器工作示意图.png
G1收集的阶段.png
11. 吞吐量 = 运行用户代码时间/(运行用户代码时间 + 垃圾收集时间)
12. 垃圾收集时间 = 垃圾回收频率 * 单次垃圾回收时间
13. 未来的垃圾回收器,JDK11中的ZGC,一种可扩展的低延迟垃圾收集器
1> 处理TB量级的堆
2> GC时间不超过10ms
3> 与使用G1相比,应用吞吐量的降低不超过15%
4> 实现技术:有色指针和加载屏障
14. Stop The World现象:无法避免,调优尽量减少
-
内存分配与回收策略
- 对象优先在Eden分配:如果内存Eden空间不足,就会发生Minor GC
- 大对象直接进入老年代:大对象:很长的字符串和大型数组。
1> 导致内存有空间,提前垃圾回收来放他们
2> 进行大量的内存复制,影响Minor GC。
3> -XX:PretenureSizeThreshold 参数 :大于参数值直接在老年代分配,缺省为0 表示绝不会直接分配在老年代 - 长期存活的对象将进入老年代,默认15
1> -XX:MaxTenuringThreshold 参数 - 动态对象年龄判定
- 空间分配担保
1> 大量的对象存活,survival空间不够,只要老年代连续空间大于新生代对象的总大小或者历次晋升的平均大小,就进行MinorGC,否则Full GC
-
内存泄漏和内存溢出辨析
- 内存溢出是对象数据太多,超过了给定的内存空间
- 内存泄漏是指大量无用的对象一直未被回收,导致给定的虚拟机内存不够使用。譬如集合等容器中的对象一直往里面添加数据,不使用的也不清理
-
JDK为我们提供的工具
- jps 虚拟机进程状况工具,列出当前机器上正在运行的虚拟机进程
- jstat 虚拟机统计信息监视工具
1> 假设需要每250毫秒查询一次进程2764垃圾收集状况,一共查询20次,那命令是:jstat -gc 2764(jvm进程号) 250 20
2> -class 类加载器
3> -compiler JIT
4> -gc GC堆状态
5> -gccapacity 各区大小
6> -gccause 最近一次GC统计和原因
7> -gcnew 新区统计
8> -gcnewcapacity 新区大小
9> -gcold 老区统计
10> -gcpermcapacity 永久区大小
11> -gcutil GC统计汇总
12> -printcompilation HotSpot编译统计 - jinfo java 配置信息工具
1> 查看和修改虚拟机参数
2> -flag 查看虚拟机参数标记,也可以修改标记 - jmap java内存映像工具
1> 在windows下受限 - jhat 虚拟机堆转存储快照分析工具
- jstack java堆栈跟踪工具
- jConsole java监视与管理控制台
1>管理远程进程
a, -Djava.rmi.server.hostname=..
b, -Dcom.sun.management.jmxremote
c, -Dcom.sun.management.jmxremote.port=8888
d, -Dcom.sun.management.jmxremote.authenticate=false
e, -Dcom.sun.management.jmxremote.ssl=false - VisualVM 多合一故障处理工具
- 通过代码获取栈信息Thread.getAllStackTrace()
-
了解MAT:一种eclipse的独立插件用于分析内存使用的工具,可以分析是否有内存泄漏等
-
浅堆和深堆
1)浅堆 这个对象的结构本身所占有的内存大小
2)深堆 这个对象被GC回收后,可以真实释放的内存大小 -
可以使用ManagementFactory类获取虚拟机的信息
网友评论