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

java内存溢出怎么排查

  • 内存
  • 2024-09-05 08:54:55
  • 3511

一、记一次线上内存溢出问题排查过程业务反馈后台管理页面打不开,报错。后台日志显示zookeeper无法连接,找不到Dubbo服务提供者。之前我用其他在线服务连接ZooKeeper时出现问题,导致内存溢出,日志中出现OutOfMemory错误,所以我直接去服务器检查内存使用情况。使用ps-ef|grepjava命令检查Java进程号,使用jmap-heappid命令检查jvm堆内存使用情况。结果如下:正如你所看到的。,堆内存使用率为100%。
现在您知道服务因内存溢出而崩溃,您需要导出堆内存映像进行分析。使用ps-ef|grepjava命令显示堆内存溢出时维护的日志文件的路径。简单说明一下:您需要在启动Java程序时添加一个参数,以便在发生堆内存溢出时自动生成hprof文件。参数:-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=文件路径。获取堆内存镜像后,请尽快重启并恢复在线服务。下一步是分析过程。使用EclipseMemoryAnalysisTools(MAT)工具进行分析。我第一次在MacOS上使用这个工具时,遇到了两个小问题。
1.打开工具时出错:/private/var/folders/8m/tgf解决方法:右键单击mat工具。要查看包的内容并找到并修改,请添加参数:-data下一行是数据存储路径。
2.打开镜像文件时,出现错误:Aninternalerroroccurredduring:"ParsingheapdumpfromXXX,我的镜像文件有2G多,但是MemoryAnalyzerini文件中的参数-Xmx1024m默认只有1G,因此将此参数更改为-Xmx4096m。
文件成功打开后,选择查看可能的泄漏对象。


二、java的内存异常问题,怎么解决Java中常见的几种内存溢出及解决方法【场景一】:
emoryError:Javaheapspace:这是因为Java堆内存不够导致的。原因之一是它确实不够(例如太多)。递归级别等),另一个原因是程序存在死循环;
如果Java堆内存不够,可以通过调整JVM的如下配置来解决:
-Xms3062m
-Xmx3062m
[场景2]
emoryError:GCoverheadlimitexceeded
[说明]:JDK6新增了一个错误类型,当GC采取长时间释放小空间;这通常是因为堆太小,导致内存不足而导致异常。
[解决办法]:
1.检查系统是否存在使用大内存或无限循环的代码;
2.通过添加JVM配置来限制内存使用:
-XX:-UseGCOverheadLimit
[情况3]:
emoryError:PermGenspace:这是因为P区内存不足。可以调整JVM配置:
-XX:MaxPermSize=128m
-XXermSize=128m
【注意】:
JVM的Perm区域主要用于存储类和元数据信息。当类被Loader加载时,就会使用它。会被放到PermGenspace中,这个区域会变旧,主程序运行时GC不会清理旧区域。如果程序需要加载大量对象,则默认大小为64MB。超过64MB,这部分内存就会溢出。您需要增加内存分配。通常128MB就足够了。
[情况4]:
emoryError:Directbuffermemory
调整-XX:MaxDirectMemorySize=参数,例如添加JVM配置:
-XX:MaxDirectMemorySize=128m
[情况5]:
emoryError:unabletocreatenewnativethread
[原因]:没有足够的堆栈空间来创建额外的线程,或者创建了太多线程,或者堆栈空间真的很小。
【解决办法】:由于JVM没有提供设置总栈空间大小的参数,因此可以设置单线程栈的大小,系统总用户空间为3G,Text/除外;Data/BSS/MemoryMapping段此外,堆和堆栈空间的总量是有限的,并且它们可以按比例缩放。因此,如果遇到这个错误,可以通过两种方式解决:1、通过-Xss启动参数减小单个线程栈的大小,这样就可以开启更多的线程(当然不能太多小,太小了)将导致StackOverflowError);2、通过--Xms-Xmx这两个参数减少Heap的大小,将内存让给Stack(前提是Heap空间足够)。
[情况6]:
verflowError
[原因]:这也是一种内存溢出错误,即线程堆栈溢出,或者方法调用层次过多(如存在无限递归调用)或者线程栈太小。
【解决方案】:优化程序设计,减少方法调用次数;调整-Xss参数以增加线程堆栈大小。
三、java内存溢出的问题如何排查众所周知,在Java程序中,内存溢出是一个常见的错误。我们先从基本分析开始吧!
内存溢出是由于太多未引用的对象(垃圾)导致的内存溢出,导致JVM无法及时回收它们。如果出现这种现象,可以进行代码排查:
1)如果在类中使用了过多的静态修改(例如publictaitc),并且在应用程序中引用变量时,在类的属性中使用静态修改时最好这样做所以;仅使用基本类型或字符串。如publicstaticinti=0;//publicstaticStringstr;
2)如果应用程序使用大量递归或无限递归(递归使用大量新对象)
3)如果应用程序使用大量循环或者无限循环(循环中使用大量新创建的对象)
4)检查应用程序是否对所有记录都使用数据库查询方法。即并发轮询方式如果数据量超过10万条可能会导致内存溢出,因此查询时应使用“分页查询”。
5)检查是否存在存储对象引用而不是对象的数组、列表或映射,因为这些引用会阻止相应的对象被释放。将大量存储在内存中。
6)检查是否使用了“非文字字符串+”操作。由于String类的内容是不可变的,因此每次执行“+”时都会生成新的对象。如果太多,就会导致new的String对象过多,导致JVM无法及时回收,造成内存丢失。溢出。
如Strings1="Myname";
Strings2="is";
Strings3="xuwei";
Stringstr=s1+s2+s3+......;这样很容易造成内存溢出
但是Stringstr="Myname"+"is"+"xuwei"+"nice"+"to"+"meetyou";//但是这样不会造成内存溢出。由于它是一个“字符串文字”,因此当执行“+”时,它就会在编译时执行。不会按照JVM执行。
使用String、StringBuffer和StringBuilder时,如果是“+”的字面字符串,应使用String以获得最佳性能;如果是“+”的String类,如果不考虑线程安全,就应该使用String。选择StringBuilder效果最好。
知道原因后,解决办法就很简单了。