什么是内存泄漏? 什么是内存溢出
内存溢出: OutOfMemory
它是指程序在申请内存时,没有足够的内存空间供其使用,抛出 OutOfMemory 错误
内存泄露: Memory Leak
它是指程序运行后,没有释放所占用的内存空间,比如程序运行完后没有释放对象的引用,一次内存泄漏可能不会有很大的影响,但长时间的内存泄漏,堆积到一定程度就会产生内存溢出
(1)单例对象,生命周期和应用程序一样长,如果单例对象持有对外部对象的引用的话,那么这个外部对象是不能被回收的,则会产生内存泄露;
(2)一些资源未闭也会导致内存泄漏,比如数据库连接,网络连接 socket 和0 流的连接都必须在 finally 中 close,否则不能被回收的:
Linux环境下线上服务器内存占用过高排查思路
- linux命令
top
>shift+M
按内存占用将程序排序,找出内存占用高的进程,并记录PID jmap -hosto PID
查看jvm中占用内存较大的对象有哪些,信息可能较多,可以将信息输出到某个文件jmap -hosto PID >./文件名.txt
jmap -heap PID
查看jvm堆内存的使用情况jmap-dump:format=b,file=./文件名.hprof PID
jvm镜像快照,执行这个导出命令时会占用一部分内存资源,所以操作时需要谨慎操作,如果时集群部署可以先从集群中摘除;尽量在启动项目时添加
-XX:+HeapDumpOnOutofMemoryError
和-XX:HeapDumpPath=/路径/文件名.hprof
,在发生堆内存溢出时,自动导出并保存内存镜像,
MAT使用
CPU占用过高问题排查
- linux命令
top
>shift+P按内存占用将程序排序,找出CPU占用高的进程,并记录PID - linux命令
top -H -p PID
查看PID进程内所有线程占用CPU及内存的占用情况,记录占用较高的线程tid - 用
jstack PID > ./文件名.txt
输出jvm的线程详情 - 因为输出jvm线程信息线程号是用16进制保存的,所以要用
printf '%x' tid
将tid转换成16进制,然后再从第3步拿到的jvm线程详情文件中查找线程信息中的业务类,找到类以后查看对应类的代码逻辑是否有问题
JVMI 堆溢出后,其他线程是否可以继续工作
如果导致内存占用对象是局部的,那么发生内存溢出后,抛出异常后方法就出栈了,引用没有了也就回收了,所以其他线程是可以继续工作的;
但是如果导致导致内存占用高的对象是全局的,无法释放,就会导致其他线程无法访问