美文网首页运维部署
21 Jvm 调优 一篇就够

21 Jvm 调优 一篇就够

作者: starQuest | 来源:发表于2022-07-08 11:35 被阅读0次

    案例一 xxx项目 内存溢出

    image.png

    ① jps -l -v

    image.png

    ② jstack 155234

    image.png

    jstack 155234 >jstack.log

    jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。

    一:jstack

    jstack命令的语法格式: jstack <pid>。可以用jps查看java进程id。这里要注意的是:

    1. 不同的 JAVA虚机的线程 DUMP的创建方法和文件格式是不一样的,不同的 JVM版本, dump信息也有差别。

    2. 在实际运行中,往往一次 dump的信息,还不足以确认问题。建议产生三次 dump信息,如果每次 dump都指向同一个问题,我们才确定问题的典型性。

    二:jstack Dump 日志文件中的线程状态

    1:dump 文件里,值得关注的线程状态有

    死锁, Deadlock(重点关注)

    执行中,Runnable

    等待资源, Waiting on condition(重点关注)

    等待获取监视器, Waiting on monitor entry(重点关注)

    暂停,Suspended

    对象等待中,Object.wait() 或 TIMED_WAITING

    阻塞, Blocked(重点关注)

    停止,Parked

    2:Dump文件中的线程状态含义及注意事项

    Deadlock:死锁线程,一般指多个线程调用间,进入相互资源占用,导致一直等待无法释放的情况。

    Runnable:一般指该线程正在执行状态中,该线程占用了资源,正在处理某个请求,有可能正在传递SQL到数据库执行,有可能在对某个文件操作,有可能进行数据类型等转换。

    Waiting on condition:该状态出现在线程等待某个条件的发生。具体是什么原因,可以结合 stacktrace来分析。最常见的情况是线程在等待网络的读写,比如当网络数据没有准备好读时,线程处于这种等待状态,而一旦有数据准备好读之后,线程会重新激活,读取并处理数据。在 Java引入 NewIO之前,对于每个网络连接,都有一个对应的线程来处理网络的读写操作,即使没有可读写的数据,线程仍然阻塞在读写操作上,这样有可能造成资源浪费,而且给操作系统的线程调度也带来压力。在 NewIO里采用了新的机制,编写的服务器程序的性能和可扩展性都得到提高。

        如果发现有大量的线程都在处在 Wait on condition,从线程 stack看, 正等待网络读写,这可能是一个网络瓶颈的征兆。因为网络阻塞导致线程无法执行。一种情况是网络非常忙,几 乎消耗了所有的带宽,仍然有大量数据等待网络读 写;另一种情况也可能是网络空闲,但由于路由等问题,导致包无法正常的到达。所以要结合系统的一些性能观察工具来综合分析,比如 netstat统计单位时间的发送包的数目,如果很明显超过了所在网络带宽的限制 ; 观察 cpu的利用率,如果系统态的 CPU时间,相对于用户态的 CPU时间比例较高;如果程序运行在 Solaris 10平台上,可以用 dtrace工具看系统调用的情况,如果观察到 read/write的系统调用的次数或者运行时间遥遥领先;这些都指向由于网络带宽所限导致的网络瓶颈。另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。
    

    locked:线程阻塞,是指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。

    Waiting for monitor entry 和 in Object.wait():Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 monitor。

    ③ jmap -heap 155234

    image.png
    image.png

    [root@localhost ~]# jmap -heap 27900
    Attaching to process ID 27900, please wait...
    Debugger attached successfully.
    Client compiler detected.
    JVM version is 20.45-b01
    using thread-local object allocation.
    Mark Sweep Compact GC
    Heap Configuration: #堆内存初始化配置
    MinHeapFreeRatio = 40 #-XX:MinHeapFreeRatio设置JVM堆最小空闲比率
    MaxHeapFreeRatio = 70 #-XX:MaxHeapFreeRatio设置JVM堆最大空闲比率
    MaxHeapSize = 100663296 (96.0MB) #-XX:MaxHeapSize=设置JVM堆的最大大小
    NewSize = 1048576 (1.0MB) #-XX:NewSize=设置JVM堆的‘新生代’的默认大小
    MaxNewSize = 4294901760 (4095.9375MB) #-XX:MaxNewSize=设置JVM堆的‘新生代’的最大大小
    OldSize = 4194304 (4.0MB) #-XX:OldSize=设置JVM堆的‘老生代’的大小
    NewRatio = 2 #-XX:NewRatio=:‘新生代’和‘老生代’的大小比率
    SurvivorRatio = 8 #-XX:SurvivorRatio=设置年轻代中Eden区与Survivor区的大小比值
    PermSize = 12582912 (12.0MB) #-XX:PermSize=<value>:设置JVM堆的‘持久代’的初始大小
    MaxPermSize = 67108864 (64.0MB) #-XX:MaxPermSize=<value>:设置JVM堆的‘持久代’的最大大小
    Heap Usage:
    New Generation (Eden + 1 Survivor Space): #新生代区内存分布,包含伊甸园区+1个Survivor区
    capacity = 30212096 (28.8125MB)
    used = 27103784 (25.848182678222656MB)
    free = 3108312 (2.9643173217773438MB)
    89.71169693092462% used
    Eden Space: #Eden区内存分布
    capacity = 26869760 (25.625MB)
    used = 26869760 (25.625MB)
    free = 0 (0.0MB)
    100.0% used
    From Space: #其中一个Survivor区的内存分布
    capacity = 3342336 (3.1875MB)
    used = 234024 (0.22318267822265625MB)
    free = 3108312 (2.9643173217773438MB)
    7.001809512867647% used
    To Space: #另一个Survivor区的内存分布
    capacity = 3342336 (3.1875MB)
    used = 0 (0.0MB)
    free = 3342336 (3.1875MB)
    0.0% used
    tenured generation: #当前的Old区内存分布
    capacity = 67108864 (64.0MB)
    used = 67108816 (63.99995422363281MB)
    free = 48 (4.57763671875E-5MB)
    99.99992847442627% used
    Perm Generation: #当前的 “持久代” 内存分布
    capacity = 14417920 (13.75MB)
    used = 14339216 (13.674942016601562MB)
    free = 78704 (0.0750579833984375MB)
    99.45412375710227% used

    ③ jmap -histo 155234

    jmap -histo:live 155234

    jmap -histo:live 6987 | sort -n -r -k 2 | head -20

    jmap -histo 155234 > jmap-histo.log

    image.png

    instance 是对象的实例个数

    bytes 是总占用的字节数

    class name 对应的就是 Class 文件里的 class 的标识

    B 代表 byte

    C 代表 char

    D 代表 double

    F 代表 float

    I 代表 int

    J 代表 long

    Z 代表 boolean

    前边有 [ 代表数组, [I 就相当于 int[]

    对象用 [L+ 类名表示

    ④jstat -gc 155234 5000 20

    <u>https://blog.csdn.net/u010648555/article/details/81089323</u>

    image.png

    S0C:年轻代第一个survivor的容量(字节)

    S1C:年轻代第二个survivor的容量(字节)

    S0U:年轻代第一个survivor已使用的容量(字节)

    S1U:年轻代第二个survivor已使用的容量(字节)

    EC:年轻代中Eden的空间(字节)

    EU:年代代中Eden已使用的空间(字节)

    OC:老年代的容量(字节)

    OU:老年代中已使用的空间(字节)

    MC:方法区的容量

    MU:方法区已使用的容量

    CCSC:压缩类容量

    CCSU:压缩类空间使用大小

    YGC:从应用程序启动到采样时年轻代中GC的次数

    YGCT:从应用程序启动到采样时年轻代中GC所使用的时间(单位:S)

    FGC:从应用程序启动到采样时老年代中GC(FULL GC)的次数

    FGCT:从应用程序启动到采样时老年代中GC所使用的时间(单位:S)

    GCT:垃圾回收消耗总时间

    ⑤jstat -gcutil 155234 5000 20

    image.png

    S0:幸存1区当前使用比例

    S1:幸存2区当前使用比例

    E:伊甸园区使用比例

    O:老年代使用比例

    M:元数据区使用比例

    CCS:压缩使用比例

    YGC:年轻代垃圾回收次数

    FGC:老年代垃圾回收次数

    FGCT:老年代垃圾回收消耗时间

    GCT:垃圾回收消耗总时间

    三:jvm参数调优

    nohup java -jar -Xms2048M -Xmx4096M -Xmn2048M -XX:MaxNewSize=2048M -XX:MaxPermSize=200M -XX:MaxGCPauseMillis=20 -XX:-HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/zysco/dump/websocket.hprof -XX:+DisableExplicitGC -XX:InitiatingHeapOccupancyPercent=50 -XX:G1HeapWastePercent=10 xxx项目.jar --spring.profiles.active=pro,redis-cluster,kafka-pro,zk-pro,redisLock-pro,tsdb-pro,mongo-pro >/dev/null 2>&1 &

    参考
    https://www.cnblogs.com/juzii/p/5973516.html

    相关文章

      网友评论

        本文标题:21 Jvm 调优 一篇就够

        本文链接:https://www.haomeiwen.com/subject/olzsvrtx.html