美文网首页
java中常见的线上问题(OOM, CPU过载)

java中常见的线上问题(OOM, CPU过载)

作者: suxin1932 | 来源:发表于2020-06-21 18:32 被阅读0次

1.OOM

1.1 常见原因

>> 内存分配确实过小
>> 频繁创建对象,没有及时释放
>> 频繁申请系统资源,导致系统资源耗尽(例如:不断创建线程,不断发起网络连接)

1.2 定位与解决方法

#需要先找到出问题的进程,使用top命令定位:
输入top命令后,可以按P(shift+p)根据cpu占用排序、按M根据内存占用排序、按T根据运行时间排序。
(可以先按c显示具体的command)

#这里先按M根据内存排序查找异常的进程:
这里假设出现异常的进程pid为28613

#注意
定位问题前请先尝试输入jps命令,确定是否能够显示出现问题的pid(例如28613).
如果jps没有相应的显示,可能是你当前用户的权限不够,
请使用启用相应进程的用户或者拥有更高权限的用户排查问题!
不然以下的一些命令(例如jmap)将无法使用.

#原理
java程序启动后,默认会在/tmp/hsperfdata_userName目录下以该进程的id为文件名新建文件,
并在该文件中存储jvm运行的相关信息,其中的userName为当前的用户名,
/tmp/hsperfdata_userName目录会存放该用户所有已经启动的java进程信息.
而jps、jconsole等工具的数据来源就是这个文件(/tmp/hsperfdata_userName/pid)。
所以当该文件不存在或是无法读取时就会出现jps无法查看该进程号,jconsole无法监控等问题

1.2.1 判断是否是由于“内存分配确实过小”

#输入以下命令, 可以看到详细的堆内存使用情况,可以以此判断应用分配的内存是否确实过小
jmap -heap 28613

1.2.2 判断是否是由于“频繁创建对象,没有及时回收”

#输入以下命令,找出最耗内存的对象
jmap -histo:live 28613 | more

#输入命令后,会以表格的形式显示存活对象的信息,并按照所占内存大小排序
[root@bogon~]# jmap -histo:live 2879 | more
 num     #instances         #bytes  class name
----------------------------------------------
   1:         81515       11259264  [C
   2:         80010        1920240  java.lang.String
   3:         44265        1416480  java.util.concurrent.ConcurrentHashMap$Node
   4:          4057        1369872  [B
   5:         11200        1241976  java.lang.Class
   6:          8977         789976  java.lang.reflect.Method
   7:         18801         752040  java.util.LinkedHashMap$Entry
   8:          5144         627336  [I
   9:         11948         601184  [Ljava.lang.Object;
  10:          8275         595352  [Ljava.util.HashMap$Node;
  11:         18231         583392  java.lang.ref.WeakReference
  12:          9847         551432  java.util.LinkedHashMap
  13:           375         544288  [Ljava.util.concurrent.ConcurrentHashMap$Node;
  14:         29118         465888  java.lang.Object
  15:         13034         417088  java.util.HashMap$Node
  16:          8850         354000  java.lang.ref.SoftReference
  17:         10490         251760  java.beans.MethodRef
  18:          3586         200816  java.beans.MethodDescriptor
  19:          6450         195288  [Ljava.lang.String;

>> instances: 对象实例数量
>> bytes: 占用内存大小
>> class name: 类名
可以看到目前最耗内存的对象也才占用内存11m,所以属于正常范畴
如果发现某个对象的占用大量内存(例如:1G以上),就需要review代码,审查下该对象是否没有及时回收
jmap -heap输出的非自定义类名说明.-->最后一列class name 的解释说明png

1.2.3 判断是否是由于“频繁申请系统资源”

#查看进程的线程数量:
ll /proc/{PID}/task | wc -l
>> 执行命令
[root@bogon ~]# ll /proc/28613/task | wc -l
101
>> 可以看到,该进程使用了101个线程。
>> 如果看到启用了大量线程,就需要审查代码涉及到线程池的使用部分,是否限定了最大线程数量。

#查询进程占用的句柄数量
ll /proc/{PID}/fd | wc -l
>> 执行命令
[root@bogon~]# ll /proc/28613/fd | wc -l
38

>> 可以看到,该进程使用了38个文件句柄。
>> 如果占用大量文件句柄,需要审查代码中涉及到文件操作和网络连接操作是否有及时关闭资源链接。

参考资源
https://zacard.net/2017/08/21/howto-handle-java-oom/

相关文章

网友评论

      本文标题:java中常见的线上问题(OOM, CPU过载)

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