带你解决java内存爆炸和CPU100%的问题
今天给java开发伙伴们分享一个如何对线上项目进行内存和CPU问题分析、定位和解决的方法。相信大多时候我们的工作流程是业务开发,开发完后自己用示例测试,测试好了和前端集成,测试版本发布后如果有测试部门进行一系列的测试,最终给用户部署版本。而测试在因为一些测试盲区导致某些方法未经测试进行部署,而在使用中发现有内存占用比例高,或CPU100%的问题。而对线上项目问题排查能力是DevOps或者中高级工程
java - 内存爆炸、CPU100% 问题分析、定位与解决
背景
今天给java开发伙伴们分享一个如何对线上项目进行内存和CPU问题分析、定位和解决的方法。相信大多时候我们的工作流程是业务开发,开发完后自己用示例测试,测试好了和前端集成,测试版本发布后如果有测试部门进行一系列的测试,最终给用户部署版本。
而测试在因为一些测试盲区导致某些方法未经测试进行部署,而在使用中发现有内存占用比例高,或CPU100%的问题。
而对线上项目问题排查能力是DevOps或者中高级工程师需要掌握的一项技能。
堆内存溢出
问题思路整理
1、堆内存什么情况会溢出 ?
当资源申请内存时候,申请内存大小超过了剩余可申请大小会抛出OutOfMeMoryError。
2、如何定位申请大量内存的函数?
当内存溢出抛出异常,程序会终止服务,则不能使用jmap获取,需要进行配置获取内存异常保存快照设置。
3、查找申请内存函数的具体代码类和方法。
使用工具定位问题代码位置。
-
堆内存申请
配置vm 内存 -Xms256m -Xmx256m
byte[] buff = new byte[256 * 1204 * 1024]; -
定位申请内存的代码位置
在内存溢出时候,程序会因为抛出异常而终止运行,则需要在抛出异常退出前对内存进行快照保存,以完成代码问题的位置和原因内存快照
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:\dump2.hprof
也可以对正在运行jvm程序进行手动快照保存
#jmap -dump:live,format=b,file=heap.bin <pid>
java工具 visualVM
对于查看内存快照可以使用 java visualVM 对快照进行加载进行分析
通过该工具可以查看到内存占用情况
很多人都应该对 visualVM 是jvm提供的一个工具,可以对内存快照进行剖析,了解到该快照的内部情况,但这里对于分析内存调用方法显然不太直观。
接下来给大家推荐MAT工具。MAT
通过加载内存快照显示对应的快照页面。
点击 Leak Suspects
从上面的Problem Suspect会列出可能引发内存溢出的问题代码类的位置,有目的类就可以快速定位到对应方法。
MAT调试工具使用可以通过独立下载,也可以作为插件使用。
堆外内存分析
问题思路整理
1、为什么要使用堆外内存 ?
一些底层工具为了实现一些特殊方法或者为了追求效率,会使用到unsafe申请堆外内存。
2、堆外内存什么情况会溢出 ?
同堆内内存溢出道理相同,不过抛出异常为 OutOfMeMoryError: Direct buffer memory。
3、如何定位申请大量内存的函数?
因为是堆外内存溢出,通过配置堆内存异常快照,无法在堆外异常时候保存快照,则需要使用第三方调优工具代替jvm申请内存。
4、根据第三方调优工具提供的内存申请日志,查找有大量内存申请的方法,定位到问题代码位置
1、已知调用排查方法
一般使用堆外内存我们会使用到ButeBuffer.allocaeDirect方法。
我们使用到BTrace进行方法定位。
BTrace的使用
1)BTrace 插件
在jdk 中 visualVm工具安装BTrace插件
在需要排查的java进行打开BTrace
添加脚本
点击 start,如果有代码调用该方法,则会在控制台显示,进行精准定位。
2)BTrace命令
一般在服务器使用到Linux,如果没有X server,则BTrace命令方法更适合
在代码中编写btrace脚本
@BTrace
public class TracingScript {
/* put your code here */
@OnMethod{
clazz = "java.nio.ByteBuffer",
method = "allocateDirect"
}
public static void traceExecute() {
println("who call ByteBuffer.allocateDirect :");
jstack();
}
}
进入到项目目录内,执行以下命令
bin/btrace -cp build/ pid /tracePath/TracingSript
则当有调用会在命令中打印显示。
2、未知方法排查
通过上面已知方法可以进行快速定位,但对于未知方法则无法使用到BTrace进行定位,但jvm无法监视到堆外内存,则需要使用到gperftools工具
gperftools 是谷歌提供的一个工具,可以替代jvm进行堆内外内存申请,该工具不用做第三方引擎,而用来作为调优工具进行问题排查。
使用逻辑图
1) 安装libunwind
tar -zxvf libunwind-1.1.tar.gz
cd libunwind-1.1
//配置
./configure --prefix=/root/tools/libunwind-1.1/ CFLAGS=-U_FORTRIFY_SOURCE
...
make
2) 安装 gperftools
tar -zxvf gperftools-2.7.tar.gz
cd gperftools-2.7
//配置
./configure --prefix=/root/tools/gperftools-2.7 LDFLAGS=-L/root/tools/libunwind=1.1/lib CPPFLAGS=-L/root/tools/libunwind-1.1/include
...
make
make install
3) 存放日志配置
mkdir -p /root/tools/gperftool-heap
//配置环境
export HEAPPROFILE=/root/tool/gperftool-heap/heap
//配置不再使用原来引擎,使用新的引擎
export LD_PRELOAD=/root/tools/gperftools-2.7/lib/libtcmalloc.so
4) 使用
#启动进程
java -classpath subject-1.jar com.study.jvm.Demo -XX:MaxDirectMemorySize=128m -XX:+HeapDumpOnOutOfMemoryError
dump快照日志
抛出异常
问题定位,查看快照日志
以便方便查找对日志重定向到txt
cd gperftools2.7/bin
//对日志重定向到txt
./pprof --text $JAVA_HOME/bin/java /root/tools/gperftool-heap/heap.0003.heap > result.txt
more result.txt
定位问题
通过以上定位找到了调用类和方法的使用。
接下来就可以使用上述 已知调用排查方法 进行代码位置定位。
CPU 100%问题排查
引发原因
1、cpu100%是如何引起的?
cpu满负荷时就会导致cpu100%。
2、如何查找问题代码位置?
找到问题代码进程,通过jdk命令查看下进程
1)CPU满负荷
在一段代码中,如果没有阻塞代码并且cpu资源释放代码,则会导致cpu100%,也就是我们所说的死循环计算代码。
例如以下代码会导致cpu100%。
while(true) {
new Random().next();
}
2)问题代码定位
通过top -p pod 命令查看java 进程cpu占用情况。
通过快捷键 Shift + H
则可以查看到每个线程的cpu占用情况。
通过jstack 1959 > cpu.txt
,对进程 1959 转换十六进制 为 0x63C
查看结果:
3)cpu100%线上处理
如果生产CPU100%会出现什么问题,如何解决?
外网如果登录则无法进行访问
切断外网请求访问,让cpu慢慢冷静下来。
如果业务数据不严重,则重启下服务器吧。
更多推荐
所有评论(0)