1.什么是垃圾

没有引用指向的对象

C语言申请内存:malloc free C++: new delete Java: new ? 自动内存回收,编程上简单,系统不容易出错,手动释放内存,容易出两种类型的问题:

  1. 忘记回收
  2. 多次回收

没有任何引用指向的一个对象或者多个对象(循环引用)

2.如何定位垃圾

  1. 引用计数 无法解决循环引用

选区_127.png

  1. 根可达算法(根搜索算法 Root Searching) 解决循环引用

根对象是什么:
root.jpg

  1. 线程栈变量

main()会起一个main线程,线程里面有一个main栈针图片.png,栈针里面会有变量

  1. 静态变量
  2. 常量池

    1. Java中的常量池,实际上分为两种形态:**静态常量池**和**运行时常量池**。<br /> 所谓**静态常量池**,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分空间。这种常量池主要用于存放两大类常量:**字面量**(Literal)和**符号引用量**(Symbolic References),字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等,符号引用则属于编译原理方面的概念,包括了如下三种类型的常量:
  • 类和接口的全限定名
  • 字段名称和描述符
  • 方法名称和描述符

    运行时常量池,则是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。
    c. JNI指针
    调用C C++ 本地方法所用到的那些个对象

    3.常见的垃圾回收算法

  1. 标记清除(mark-sweep) - 位置不连续 产生碎片

算法相对简单,存活对象多的时候效率较高
两边扫描(先找不可回收的,标记,然后再找可回收的),效率偏低
容易产生碎片

  1. 拷贝算法 - 没有碎片,浪费空间

图片.png

  1. 适用于存活对象较少的情况,只扫描一遍,效率提高,没有碎片
  2. 空间浪费,移动复制对象,需要调整引用
    1. 标记压缩 - 没有碎片,效率偏低
  3. 不会产生碎片,方便对象分配,不会产生内存减半
  4. 扫描两次(第一遍找出有用的块,第二遍移动,多线程可能还会有问题),需要移动对象,效率偏低

    4.JVM内存分代模型(用于分代垃圾回收算法)

    image.png
  1. 部分垃圾回收器使用的模型

    除Epsilon ZGC Shenandonah 之外的GC都是使用逻辑分代模型 G1是逻辑分代 物理不分代 除此之外不仅逻辑分代,而且物理分代

  2. 新生代 + 老年代 + 永久代(1.7)/ 元数据区(1.8) Metaspace

    1. 永久代 元数据 - Class
    2. 永久代必须指定大小限制 ,元数据可以设置,也可以不设置,无上限(受限于物理内存)
    3. 字符串常量 1.7 - 永久代,1.8 - 堆
    4. MethodArea逻辑概念 - 永久代、元数据
  3. 新生代 = Eden + 2个suvivor区
    1. YGC回收之后,大多数的对象会被回收,活着的进入s0
    2. 再次YGC,活着的对象eden + s0 -> s1
    3. 再次YGC,eden + s1 -> s0
    4. 年龄足够 -> 老年代 (15 CMS 6)
    5. s区装不下 -> 老年代
  4. 老年代
    1. 顽固分子
    2. 老年代满了FGC Full GC
  5. GC Tuning (Generation)
    1. 尽量减少FGC
    2. MinorGC = YGC
    3. MajorGC = FGC
  6. 动态年龄:(不重要)

s1->s2超过50%,直接将年龄最大的放入old区
图片.png
https://www.jianshu.com/p/989d3b06a49d

  1. 分配担保:(不重要) YGC期间 survivor区空间不够了 空间担保直接进入老年代 参考:https://cloud.tencent.com/developer/article/1082730

    5.常见的垃圾回收器

    2.png

    Serial

    STW
    图片.png

    Parallel Scavenge(PS) + Parallel Old(PO)

    图片.png

    ParNew(Parallel Scavenge变种以配合CMS)
  2. JDK诞生 Serial追随 提高效率,诞生了PS,为了配合CMS,诞生了PN,CMS是1.4版本后期引入,CMS是里程碑式的GC,它开启了并发回收的过程,但是CMS毛病较多,因此目前任何一个JDK版本默认是CMS 并发垃圾回收是因为无法忍受STW

  3. Serial 年轻代 串行回收
  4. PS 年轻代 并行回收
  5. ParNew 年轻代 配合CMS的并行回收
  6. SerialOld
  7. ParallelOld
  8. ConcurrentMarkSweep 老年代 并发的, 垃圾回收和应用程序同时运行,降低STW的时间(200ms) CMS问题比较多,所以现在没有一个版本默认是CMS,只能手工指定 CMS既然是MarkSweep,就一定会有碎片化的问题,碎片到达一定程度,CMS的老年代分配对象分配不下的时候,使用SerialOld 进行老年代回收 想象一下: PS + PO -> 加内存 换垃圾回收器 -> PN + CMS + SerialOld(几个小时 - 几天的STW) 几十个G的内存,单线程回收 -> G1 + FGC 几十个G -> 上T内存的服务器 ZGC 算法:三色标记 + Incremental Update
  9. G1(10ms) 算法:三色标记 + SATB
  10. ZGC (1ms) PK C++ 算法:ColoredPointers + LoadBarrier
  11. Shenandoah 算法:ColoredPointers + WriteBarrier
  12. Eplison
  13. PS 和 PN区别的延伸阅读: ▪https://docs.oracle.com/en/java/javase/13/gctuning/ergonomics.html#GUID-3D0BB91E-9BFF-4EBB-B523-14493A860E73
  14. 垃圾收集器跟内存大小的关系
    1. Serial 几十兆
    2. PS 上百兆 - 几个G
    3. CMS - 20G
    4. G1 - 上百G
    5. ZGC - 4T - 16T(JDK13)

1.8默认的垃圾回收:PS + ParallelOld

常见垃圾回收器组合参数设定:(1.8)

  • -XX:+UseSerialGC = Serial New (DefNew) + Serial Old
    • 小型程序。默认情况下不会是这种选项,HotSpot会根据计算及配置和JDK版本自动选择收集器
  • -XX:+UseParNewGC = ParNew + SerialOld
  • -XX:+UseConc(urrent)MarkSweepGC = ParNew + CMS + Serial Old
  • -XX:+UseParallelGC = Parallel Scavenge + Parallel Old (1.8默认) 【PS + SerialOld】
  • -XX:+UseParallelOldGC = Parallel Scavenge + Parallel Old
  • -XX:+UseG1GC = G1
  • Linux中没找到默认GC的查看方法,而windows中会打印UseParallelGC
    • java +XX:+PrintCommandLineFlags -version
    • 通过GC的日志来分辨
  • Linux下1.8版本默认的垃圾回收器到底是什么?

    • 1.8.0_181 默认(看不出来)Copy MarkCompact
    • 1.8.0_222 默认 PS + PO

      GC算法的基础概念

  • Card Table 由于做YGC时,需要扫描整个OLD区,效率非常低,所以JVM设计了CardTable, 如果一个OLD区CardTable中有对象指向Y区,就将它设为Dirty,下次扫描时,只需要扫描Dirty Card 在结构上,Card Table用BitMap来实现

    案例汇总

    内存溢出的三种类型:
    1.第一种OutOfMemoryError: PermGen space,发生这种问题的原意是程序中使用了大量的jar或class
    2.第二种OutOfMemoryError: Java heap space,发生这种问题的原因是java虚拟机创建的对象太多
    3.第三种OutOfMemoryError:unable to create new native thread,创建线程数量太多,占用内存过大

  1. 如果有一个系统,内存一直消耗不超过10%,但是观察GC日志,发现FGC总是频繁产生,会是什么引起的? System.gc(),可能是引用了某些class

    GC常用参数

  • -Xmn -Xms -Xmx -Xss 年轻代 最小堆 最大堆 栈空间
  • -XX:+UseTLAB 使用TLAB,默认打开
  • -XX:+PrintTLAB 打印TLAB的使用情况
  • -XX:TLABSize 设置TLAB大小
  • -XX:+DisableExplictGC System.gc()不管用 ,FGC
  • -XX:+PrintGC
  • -XX:+PrintGCDetails
  • -XX:+PrintHeapAtGC
  • -XX:+PrintGCTimeStamps
  • -XX:+PrintGCApplicationConcurrentTime (低) 打印应用程序时间
  • -XX:+PrintGCApplicationStoppedTime (低) 打印暂停时长
  • -XX:+PrintReferenceGC (重要性低) 记录回收了多少种不同引用类型的引用
  • -verbose:class 类加载详细过程
  • -XX:+PrintVMOptions
  • -XX:+PrintFlagsFinal -XX:+PrintFlagsInitial 必须会用
  • -Xloggc:opt/log/gc.log
  • -XX:MaxTenuringThreshold 升代年龄,最大值15
  • 锁自旋次数 -XX:PreBlockSpin 热点代码检测参数-XX:CompileThreshold 逃逸分析 标量替换 … 这些不建议设置

    Parallel常用参数

  • -XX:SurvivorRatio

  • -XX:PreTenureSizeThreshold 大对象到底多大
  • -XX:MaxTenuringThreshold
  • -XX:+ParallelGCThreads 并行收集器的线程数,同样适用于CMS,一般设为和CPU核数相同
  • -XX:+UseAdaptiveSizePolicy 自动选择各区大小比例

    拓展

  1. -XX:MaxTenuringThreshold控制的是什么? A: 对象升入老年代的年龄 B: 老年代触发FGC时的内存垃圾比例
  2. 生产环境中,倾向于将最大堆内存和最小堆内存设置为:(为什么?) A: 相同 B:不同
  3. JDK1.8默认的垃圾回收器是: A: ParNew + CMS B: G1 C: PS + ParallelOld D: 以上都不是
  4. 什么是响应时间优先?
  5. 什么是吞吐量优先?
  6. ParNew和PS的区别是什么?
  7. ParNew和ParallelOld的区别是什么?(年代不同,算法不同)
  8. 长时间计算的场景应该选择:A:停顿时间 B: 吞吐量
  9. 大规模电商网站应该选择:A:停顿时间 B: 吞吐量
  10. HotSpot的垃圾收集器最常用有哪些?
  11. 常见的HotSpot垃圾收集器组合有哪些?
  12. JDK1.7 1.8 1.9的默认垃圾回收器是什么?如何查看?
  13. 所谓调优,到底是在调什么?
  14. 如果采用PS + ParrallelOld组合,怎么做才能让系统基本不产生FGC
  15. 如果采用ParNew + CMS组合,怎样做才能够让系统基本不产生FGC
    1.加大JVM内存
    2.加大Young的比例
    3.提高Y-O的年龄
    4.提高S区比例
    5.避免代码内存泄漏
  16. G1是否分代?G1垃圾回收器会产生FGC吗?
  17. 如果G1产生FGC,你应该做什么?
    1. 扩内存
    2. 提高CPU性能(回收的快,业务逻辑产生对象的速度固定,垃圾回收越快,内存空间越大)
    3. 降低MixedGC触发的阈值,让MixedGC提早发生(默认是45%)
  18. 问:生产环境中能够随随便便的dump吗? 小堆影响不大,大堆会有服务暂停或卡顿(加live可以缓解),dump前会有FGC
  19. 问:常见的OOM问题有哪些? 栈 堆 MethodArea 直接内存

    参考资料

  20. https://blogs.oracle.com/jonthecollector]([https://blogs.oracle.com/jonthecollector/our-collectors)[/our-collectors](https://blogs.oracle.com/jonthecollector/our-collectors%29[/our-collectors)]([https://blogs.oracle.com/jonthecollector/our-collectors](https://blogs.oracle.com/jonthecollector/our-collectors))

  21. https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
  22. http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp
  23. JVM调优参考文档:https://docs.oracle.com/en/java/javase/13/gctuning/introduction-garbage-collection-tuning.html#GUID-8A443184-7E07-4B71-9777-4F12947C8184
  24. https://www.cnblogs.com/nxlhero/p/11660854.html 在线排查工具
  25. https://www.jianshu.com/p/507f7e0cc3a3 arthas常用命令
  26. Arthas手册:
    1. 启动arthas java -jar arthas-boot.jar
    2. 绑定java进程
    3. dashboard命令观察系统整体情况
    4. help 查看帮助
    5. help xx 查看具体命令帮助
  27. jmap命令参考:https://www.jianshu.com/p/507f7e0cc3a3
    1. jmap -heap pid
    2. jmap -histo pid
    3. jmap -clstats pid