阅读 100

系统优化篇——JVM调优经验总结

刚参加工作的请忽略,晦涩难懂的东西,随着脸上皱纹的增加,目光的暗淡,发量的减少慢慢的自然会知道的。版本比较老了,跟不上时代了,后面更新 g1 的,不过现在 Java 都更新到 16 了,g1 也跟不上时代了。

Jvm 内存分配

栈内存分配

保存参数、局部变量、中间计算过程和其他数据。
退出方法时,修改栈顶指针就可以把栈帧中的内容销毁。
栈的优点:存取速度比较快,仅次于寄存器,栈数据可以共享。
栈的缺点:存在栈中大小、生存期是编译时确定的,导致缺乏灵活性。

堆内存分配

堆的优点:动态分配内存空间,生存期是运行期动态分配,垃圾回收期会自动收走不再使用的空间区域。
堆的缺点:运行时动他分配内存,分配和销毁都需要占用时间,因此效率低下。

jvm 堆配置参数

-Xms 初始堆大小 -Xmx 最大堆大小 一般建议设置 -Xms = -Xmx 整个堆大小 = 年轻代大小 + 年老代大小 + 持久代大小

Jvm 内存划分

image.png

jvm 新生代

  • 新生代 = 1 个 eden 区 + 2 个 Survivor 区
  • -Xmn 年轻代大小(1.4 or lator)

   -XX:NewSize,-XX:MaxNewSize (设置年轻代大小(for 1.3/1.4))    默认大小为整个堆的 3/8

  • -XX:NewRatio 年轻代(包括 eden 区 + 2个 Survivor 区)与年老代的比值(去除年老代)

    Xms=Xmx 并且设置 Xmn 的情况下,该参数不需要进行设置

  • -XX.SurvivorRatio

    Eden 区与 Survivor 区的大小比值,设置为 8,则两个 Survivor 区与一个 Eden 区的比值为2:8,一个 Survivor 区占整个年期待的1/10

  • 用来存放JVM刚分配的Java对象

java老年代

  • 老年代=整个堆-年轻代大小-持久代大小
  • 年轻代中经过垃圾回收没有回收掉的对象被复制到年老代
  • 年老代存储对象比年轻代年龄大的多,不乏大对象
  • 新建对象也可能直接带入老年代
    • 大对象,可以通过启动参数-XX:PretenureSizeThreshold = 1024(单位字节,默认0)来代表超过多少时不在新生代分配,直接在老年代分配
    • 大数组对象,切数组中无引用的外部对象
  • 老年代大小无配置参数

java持久代

  • 持久代=整个堆-年轻代大小-老年代大小
  • -XX:PermSize -XX:MaxPermSize

    设置持久代的大小,一般情况下推荐把-XX:PermSize 和 -XX:MaxPermSize 的值设置为相同的值,因为持久代大小调整会导致堆呢村需要出发fgc

  • 存放 Class、Method 元信息、其大小与项目的规模、类、方法的数量有关。一般设置为128,足够,设置原则是预留30%的空间
  • 持久代的回收方式
    • 常量、无用的类信息
    • 对于无用类回收,必须保证以下3点:
      • 类的所有实例都已经被回收
      • 加载 ClassLoader 已经被回收
      • 类对象的 Class 对象没有被引用(即没有通过反射引用该类的地方)

哪个说用 360 垃圾清理的

360 定位垃圾

  • 引用计算算法

每个对象都有一个引用计数属性和新增一个引用时计数加1,引用设防时计数减1,计数为0时可以进行回收,该方法简单,无法解决对象相互循环引用的问题,无法精准计算计数次数。

  • GC Roots 算法

从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相链时,则证明该对象不可用,不可达对象 Java 中,GC Roots 包括: - 虚拟机栈中引用的对象 - 方法区中类静态熟悉实体引用对象 - 方法区中的常量引用对象 - 本地方法栈 JNI 引用的对象

360 清理垃圾

  1. 复制算法(Copying)
  2. 标记清除算法(Mark-Sweep)
  3. 标记整理压缩算法(Mark-Compac)

名词解释

串行回收     GCC 单线程内存回收,会暂停所有用户线程 并行回收     收集是指多个 GC 线程并行工作,但此时用户线程是暂停的,所以 Serial 是串行的,Parallel 收集器是并行的,而 CMS 收集器是并发的 并发回收     用户线程和 GC 线程同时执行不一定是并发,也可能是交替,但是总体上可以同时执行,不需要停顿用户线程(其实 CMS 中用户线程需要停顿,只是非常短,GC 线程在另一个 CPU 上执行)

垃圾收集器

Serial 回收器(串行回收器)

一个单线程的收集器,只能使用一个 CPU 或一条县城去完成垃圾收集;在进行垃圾收集时,必须暂停所有其他工作线程,直到收集完成

缺点:Stop-The-World

优点:简单,对于 CPU 情况,由于没有多线程交互开销,反而可以更高效,是一种 Client 模式下的默认新生代收集器

新生代 Serial 回收器

  1. -XX:UseSerialGC 开启

    Serial New+ Serial Old 收集器组合进行内存回收

  2. 使用复制算法

  3. 独占式垃圾回收

    一个线程进行 GC,串行。其他工作线程暂停

老年代 Serial 回收器

  1. -XX:UseSerialGC 开启

    Serial New+ Serial Old 收集器组合进行内存回收

  2. 使用标记压缩算法
  3. 串行,独占式垃圾回收

    因为内存较大原因,回收速度比新生代慢

ParNew 回收期(并行回收器)

  并行回收器是一种独占式回收器,在收集过程中,应用程序会全部暂停,但是由于并行回收器使用多线程进行垃圾回收,从而在并发比较强的 CPU 上,他产生的挺短时间短语串行回收期,但是在单个 CPU 或者并发能力弱的系统中,并行回收器的效果不会比串行回收器好,由于多线程的压力,他的事迹表现可能比串行回收器差

新生代 Parallel Scavenge 回收器

  1. 吞吐量优化回收器

    关注CPU吞吐量,即运行用户代码时间/总时间,比如 JVM 运行100分钟,其中运行用户代码99分钟,垃圾回收1分钟,则吞吐量是99%,这种收集器能最高效率的利用 CPU 适合运行后台计算

  2. -XX:+UseParallelGC开启

    使用 Parallel Scavenge+Serial Old 收集器组合回收垃圾,这种也是 Server 模式下的默认值

  3. -XX:GCTimeRatio

    设置用户执行时间占总时间的比列,默认为99,即1分钟时间处理垃圾回收

  4. -XX:+MaxGCPauseMillis

    设置GC最大停顿时间

  5. 使用复制算法

CMS(并发标记清除)回收器

运作过程分为 4 个阶段

  • 初始标记(CMS initial mark):标记 GC Roots 能直接关联到的对象
  • 并发标记(CMS concurrent mark):进行 GC RootsTracing 的过程
  • 重新标记(CMS remark):修正并发标记期间因用户程序继续运行导致标记发生改变那一部分对象的标记
  • 并发清除(CMS concurrent sweep)

其中标记和重新标记两个阶段需要 Stop-The-World ,整个过程小号最长的时间是并发标记和并发清楚过程中收集器,都可以与用户线程同时工作

  1. 标记-清除算法

    同时他是一个使用多线程并发回收的垃圾收集器

  2. -XX:ParallelCMSThreads

    手工设定 CMS 的线程数量,CMS 默认开启的线程数量是(ParallelCMSThreads+3)/4

  3. -XX:UseCONCmARKSweepGC开启

    使用 ParNew+CMS+Serial Old 收集器组合进行内存回收,Serial Old作为 CMS 出现"Concurrent Mode Failure"失败后的后备收集器使用

  4. -XX:CMSInitiatingOccupancyFraction

    设置 CMS 收集器在年老戴空间被使用多少后触发垃圾收集,默认是 68%,仅在 CMS 收集器时有效,-XX:CMSInitiatingOccupancyFraction=70

  5. -XX:+UseCMSCompacAtFullCollection

    由于 CMS 收集器会产生碎片,此参数设置在垃圾收集器后是否需要一次内存碎片整理过程,仅 CMS 收集器有效

  6. -XX:+CMSFullGCBeforeCompaction

    设置 CMS 收集器在进行若干次垃圾收集后进行内存碎片整理过程,通常与 UseCMSCompactAtFullCollection 参数一起使用

  7. -XX:CMSInitiatingPermOccupancyFraction

    设置 Perm Gen 使用达到多少比率出发,默认是92%

GC 性能指标

  • 吞吐量 应用花在非 GC 上的时间百分比
  • GC 负荷 与吞吐量相反,指应用花在 GC 上的时间百分比
  • 暂停时间 应用花在 GC Stop-The-World 的时间
  • GC 频率
  • 反应速度 从一个对象变为垃圾,这个对象的被回收时间

一个交互式的应用要求暂停时间越少越好,然后,一个非交互的应用,GC 的负荷越低越好 一个实时系统对暂停时间和 GC 负荷的要求,都是越低越好 一个嵌入式系统的 Footprint 越小越好

内存容量配置原则

  • 年轻代大小选择
    • 响应时间优先的引用,尽量设置大,直到接近系统的最低响应时间限制,在这样的情况下,年轻代收集发生频率也会最小,减少了达到老年代的对象

    • 吞吐量优先的应用,尽量设置大,可以达到 Gbit 的程度,因为对响应时间没有要求,垃圾收集可以并发进行,一般是和8 CPU 以上应用

    • 避免出现设置过小,导致 YGC 次数频繁,YGC 对象直接进入老年代,甚至老年代满了,则会触发 FGC

  • 年老代大小选择
    • 响应时间优先应用:年老戴使用并发收集器,所以其大小需要设置,一般要考虑并发会话率和会话持续时间等一些参数;如果堆设置小了,可能再乘内存碎片,高回收频率以及应用暂停而是用传统的标记清除方式;如果堆设置大了,收集的时间会比较漫长
    • 响应时间优先,并发垃圾收集信息,持久代并发收集次数,传统 GC 信息,注意年轻代和年老代回收的时间比例
    • 吞吐量优化,一般吞吐量余华引用都是一个很大的年轻代和一个很小的年老代,原因是,尽可能回收大部分的短期独享,减少中期对象,而年老代尽量存放长期存活对象。

其他

本文应该对你没用。给我个机会,我下次更新最新的。

如果觉得本文对您有帮助,请点赞分享或关注起来,如果有兴趣也可以浏览作者的其他文章。
如果觉得本文浪费了您的时间,希望评论区能留下您的宝贵意见。
如果有疑问也请留言,作者愿花时间和精力去找寻答案,一起探讨。

文章分类
后端
文章标签