备战面试日记(2.6) - (JVM.JVM调优)

备战面试日记(2.6) - (JVM.JVM调优),第1张

备战面试日记(2.6) - (JVM.JVM调优)

本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试。

记录日期:2022.1.3

大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习。

文章目录
  • JVM - JVM调优
    • JVM参数
      • JVM参数设置方法
    • JVM调优工具
      • JPS、JMAP、JSTACK
      • jconsole
      • jvisualvm
        • 使用方式
    • JVM调优方案
      • 调优原则
      • 调优目的
      • 调优方案
      • 调优步骤
        • 1.监控GC的状态
        • 2.分析结果,判断是否需要优化
        • 3.调整GC类型和内存分配
        • 4.不断的分析和调整
        • 5.全面应用参数
      • 调优实战
        • 如果你的系统CPU/内存占用100%了你怎么办?
          • CPU100%
          • 内存100%
        • 如果服务OOM,如何排查?
        • 如果系统非常卡顿,如何排查?
        • 如果你的系统忽然不能响应了你怎么排查?
        • 如果你的系统压测数据上不去你除了加负载还有没有其他的好办法?

JVM - JVM调优

jvm调优内容建议手 *** 以下,记忆深刻一点。

JVM参数

现在这里汇总一下可能会经常用到的JVM参数:

  1. -Xms20M:表示设置JVM启动内存的最小值为20M,必须以M为单位
  2. -Xmx20M:表示设置JVM启动内存的最大值为20M,必须以M为单位。将-Xmx和-Xms设置为一样可以避免JVM内存自动扩展。大的项目-Xmx和-Xms一般都要设置到10G、20G甚至还要高
  3. -verbose:gc:表示输出虚拟机中GC的详细情况
  4. -Xss128k:表示可以设置虚拟机栈的大小为128k
  5. -Xoss128k:表示设置本地方法栈的大小为128k。不过HotSpot并不区分虚拟机栈和本地方法栈,因此对于HotSpot来说这个参数是无效的
  6. -XX:PermSize=10M:表示JVM初始分配的永久代的容量,必须以M为单位
  7. -XX:MaxPermSize=10M:表示JVM允许分配的永久代的最大容量,必须以M为单位,大部分情况下这个参数默认为64M
  8. -Xnoclassgc:表示关闭JVM对类的垃圾回收
  9. -XX:+TraceClassLoading:表示查看类的加载信息
  10. -XX:+TraceClassUnLoading:表示查看类的卸载信息
  11. -XX:NewRatio=4:表示设置年轻代:老年代的大小比值为1:4,这意味着年轻代占整个堆的1/5
  12. -XX:SurvivorRatio=8:表示设置2个Survivor区:1个Eden区的大小比值为2:8,这意味着Survivor区占整个年轻代的1/5,这个参数默认为8
  13. -Xmn20M:表示设置年轻代的大小为20M
  14. -XX:+HeapDumpOnOutOfMemoryError:表示可以让虚拟机在出现内存溢出异常时Dump出当前的堆内存转储快照
  15. -XX:+UseG1GC:表示让JVM使用G1垃圾收集器
  16. -XX:+PrintGCDetails:表示在控制台上打印出GC具体细节
  17. -XX:+PrintGC:表示在控制台上打印出GC信息
  18. -XX:PretenureSizeThreshold=3145728:表示对象大于3145728(3M)时直接进入老年代分配,这里只能以字节作为单位
  19. -XX:MaxTenuringThreshold=1:表示对象年龄大于1,自动进入老年代
  20. -XX:CompileThreshold=1000:表示一个方法被调用1000次之后,会被认为是热点代码,并触发即时编译
  21. -XX:+PrintHeapAtGC:表示可以看到每次GC前后堆内存布局
  22. -XX:+PrintTLAB:表示可以看到TLAB的使用情况
  23. -XX:+UseSpining:开启自旋锁
  24. -XX:PreBlockSpin:更改自旋锁的自旋次数,使用这个参数必须先开启自旋锁
JVM参数设置方法

这里以IDEA为例:

JVM调优工具

调优工具不是要讲的重点,这些理应都应该知道,就不详细说了。

博客参考链接:Java系列笔记(4) - JVM监控与调优

jps、jstat、jhat、jinfo、jstack、jmap、jconsole、jvisualvm。这里主要清楚下jstack 和 jvisualvm,这两个比较常用。

  • jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。
  • jvisualvm是SUN/Oracle JDK自带的JVM运行状态监测工具,能够获取JVM运行状态的各种信息,包括Thread Dump和Heap Dump,在可以使用的情况下建议使用此工具监测JVM运行状态。
JPS、JMAP、JSTACK

博客参考链接:Java常用命令(一) jps、jstack、jmap

jstack:java命令–jstack 工具

jconsole

博客参考链接:JConsole可视化工具介绍

jvisualvm

博客参考链接:java jvisualvm简要说明

jvisualvm可以监控内存泄露,跟踪垃圾回收,执行时内存、cpu分析,线程分析…

jvisualvm已经被集成在jdk1.6以上的版本中(不是jre)。自身运行需要最低jdk1.6版本,但是可以监控运行在jdk1.4以上版本的java程序。

使用方式

cmd中打开直接输入”jvisualvm“。

打开jvisualvm界面。

通过可视化监控jvm信息。

JVM调优方案 调优原则
  1. 多数的Java应用不需要在服务器上进行GC优化。
  2. 多数导致GC问题的Java应用,都不是因为我们参数设置错误,而是代码问题。
  3. 在应用上线之前,先考虑将机器的JVM参数设置到最优(最适合)。
  4. 减少创建对象的数量。
  5. 减少使用全局变量和大对象。
  6. GC优化是到最后不得已才采用的手段。
  7. 在实际使用中,分析GC情况优化代码比优化GC参数要多得多。
调优目的
  • 将转移到老年代的对象数量降低到最小。
  • 减少full GC的执行时间。
调优方案
  • 减少使用全局变量和大对象。
  • 调整新生代的大小到最合适。
  • 设置老年代的大小为最合适。
  • 选择合适的GC收集器。
调优步骤 1.监控GC的状态

使用各种JVM工具,查看当前日志,分析当前JVM参数设置,并且分析当前堆内存快照和gc日志,根据实际的各区域内存划分和GC执行时间,觉得是否进行优化

2.分析结果,判断是否需要优化

如果各项参数设置合理,系统没有超时日志出现,GC频率不高,GC耗时不高,那么没有必要进行GC优化;

如果GC时间超过1-3秒,或者频繁GC,则必须优化。

注:如果满足下面的指标,则一般不需要进行GC优化:

  • Minor GC执行时间不到50ms;
  • Minor GC执行不频繁,约10秒一次;
  • Full GC执行时间不到1s;
  • Full GC执行频率不算频繁,不低于10分钟1次;
3.调整GC类型和内存分配

如果内存分配过大或过小,或者采用的GC收集器比较慢,则应该优先调整这些参数,并且先找1台或几台机器进行beta,然后比较优化过的机器和没有优化的机器的性能对比,并有针对性的做出最后选择。

4.不断的分析和调整

通过不断的试验和试错,分析并找到最合适的参数。

5.全面应用参数

如果找到了最合适的参数,则将这些参数应用到所有服务器,并进行后续跟踪。

调优实战 如果你的系统CPU/内存占用100%了你怎么办?

如果CPU和内存同时上涨,一般推测是程序的某个线程进入死循环,不停的分配内存导致。

CPU100%

参考博客链接:阿里程序员不小心把服务器CPU打到100%,淡定展示教科书排查过程

⼀般CPU100%疯狂GC,都是死循环或者产生大对象的问题。

先进入对应的服务器,⽤top -c命令找出当前进程的运⾏列表。

按⼀下P 可以按照CPU使⽤率进⾏排序。

假如说,显示Java进程 PID 为 1234 的java进程消耗最⾼。

然后我们需要根据PID 查出CPU⾥⾯消耗最⾼的进程。

使⽤命令 top -Hp 1234 找出这个进程下⾯的线程,继续按P排序。

假如说,该进程下的 2854 线程 CPU消耗最⾼。

我们要导出该进程的快照,看看该线程做了什么工作。

jstack -l 1234 > ./1234.stack

再⽤grep查看⼀下线程在⽂件⾥做了什么,b26是2854线程的16进制。

cat 1234.stack |grep 'b26' -C 8

这样就可以通过快照具体定位问题。

内存100%

一应用在性能测试过程中,发现内存占用率很高,Full GC频繁,使用sudo -u admin -H jmap -dump:format=b,file=文件名.hprof pid 来dump内存,生成dump文件,并使用Eclipse下的mat差距进行分析,发现:


从图中可以看出,这个线程存在问题,队列linkedBlockingQueue所引用的大量对象并未释放,导致整个线程占用内存高达378m,此时通知开发人员进行代码优化,将相关对象释放掉即可。

这里参考了一篇文章,在前面有表明引用。

如果服务OOM,如何排查?

一般如果出现java.lang.OutOfMemoryError: GC overhead limit exceeded。

一般都是代表为了释放很小的空间却耗费了太多的时间,其原因一般有两个:

  1. 堆太小
  2. 有死循环或大对象

如果是第一点,使用ps -ef |grep "java"查看,发现该应用使用堆过小,则只需要改变堆中各区域的大小设置即可。

如果是第二点,则可通过进程快照,根据日志找出问题代码进行修改。

如果系统非常卡顿,如何排查?

一个服务系统,经常出现卡顿,分析原因,可能是Full GC时间太长。

jstat -gcutil:
S0   S1  E   O    P    YGC YGCT FGC FGCT GCT
12.16 0.00 5.18 63.78 20.32 54  2.047 5   6.946 8.993

分析上面的数据,发现Young GC执行了54次,耗时2.047秒,每次Young GC耗时37ms,在正常范围。

而Full GC执行了5次,耗时6.946秒,每次平均1.389s,数据显示出来的问题是:Full GC耗时较长。

分析该系统的是指发现,NewRatio=9,也就是说,新生代和老生代大小之比为1:9,这就是问题的原因:

  1. 新生代太小,导致对象提前进入老年代,触发老年代发生Full GC。
  2. 老年代较大,进行Full GC时耗时较大。

优化的方法是调整NewRatio的值,调整到4,发现Full GC没有再发生,只有Young GC在执行,这就是把对象控制在新生代就清理掉,没有进入老年代。

这种做法对一些应用是很有用的,但并不是对所有应用都要这么做。

如果你的系统忽然不能响应了你怎么排查?

待补充。

如果你的系统压测数据上不去你除了加负载还有没有其他的好办法?

待补充。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5694284.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存