当前位置:首页 > 内存 > 正文

线上内存溢出排查

  • 内存
  • 2024-05-26 15:20:22
  • 402

一、记一次线上内存溢出问题排查过程业务反馈后台管理页面打不开,报错。通过后台日志发现zookeeper无法连接,找不到dubbo服务提供者。因为之前ZooKeeper出现了无法连接其他Web服务的问题,导致内存溢出,日志中出现了OutOfMemory错误,所以直接去服务器查看内存使用情况。使用ps-ef|grepjava命令找出Java进程号,然后使用jmap-heappid命令查看jvm-heap内存使用情况:
可以看到,堆内存使用情况为100%。
现在我们知道服务因内存溢出而崩溃,我们需要导出堆映像进行分析。使用ps-ef|grepjava命令查看堆溢出时维护的日志文件路径。这里说一下,启动java程序时需要添加参数,以便在发生堆溢出时自动生成hprof文件。参数:-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=文件路径。获取堆镜像后,尽快启动并恢复网络服务。下一步是分析过程。我使用EclipseMemoryAnalysisTools(MAT)工具来分析。首次在MacOS上使用该工具时出现两个小问题:
1打开该工具时出现错误,平台元数据可能写入:/private/var/folders/8m/tgf。解决方案:右键数学工具显示包内容找到并修改,添加参数:-data下一行为数据存储路径
2打开镜像文件时,出现错误:Aninternallerrooccurredduring:".parsingheapdumpfromXXX,因为我的镜像文件有2G多了,但是ini文件中的MemoryAnalyzer默认只有1G,所以把这个参数改成-Xmx4096m
选择查看LeakSuspectsReport和自动分析可能泄露的对象,如下所示:


二、java内存溢出的问题如何排查众所周知,在Java程序中,内存溢出是一个常见的错误。我们先从一些基本的分析开始吧!
内存溢出是由于太多未引用的对象(垃圾)导致JVM无法及时重新启动它们而导致的内存溢出。如果出现这样的现象,可以检查代码:
1)在类属性中使用静态修改时,是否存在过多的静态修改,例如publicstaitcStudents,以及应用程序中的引用变量;最好仅使用基本类型或字符串。例如,publicstaticinti=0;//publicstaticStringstr;
2)应用程序是否使用大量递归或无限递归(递归使用许多新对象)
3)应用程序是否使用大量循环或无限递归无限循环(循环使用大量新创建的对象)
4)检查应用程序是否使用某种方法来查询数据库中的所有记录。也就是说,如果数据量超过10万条,一次性请求的方式可能会导致内存溢出,所以请求时应该使用“分页请求”。
5)检查是否存在存储对象引用而不是对象的数组、列表或映射,因为这些引用会阻止相应的对象被释放。将大量存储在内存中。
6)检查是否使用了“非文字字符串+”操作。由于String类的内容是不可变的,因此每次运行“+”时都会创建新对象。如果new的String对象过多,就会出现过多的newString对象,导致JVM无法及时重启。并导致内存溢出。
例如Strings1="Myname";
Strings2="is";
Strings3="xuwei";
Stringstr=s1+s2+s3+......;这样很容易造成内存溢出
ButStringstr="Myname"+"is"+"xuwei"+"nice"+"to"+"meetyou";//但是这样不会造成内存溢出。由于这是一个“文字字符串”,因此运行“+”将在编译时完成。不会按照JVM执行。
使用String、StringBuffer和StringBuilder时,如果“+”使用文字字符串,则应使用String以获得更好的性能;如果“+”使用String类,如果不考虑线程安全,应该使用String。选择StringBuilder可提供更好的性能。
知道原因后,解决办法就很简单了。