运维部署

21 Jvm 调优 一篇就够

2022-07-08  本文已影响0人  starQuest

案例一 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

上一篇下一篇

猜你喜欢

热点阅读