由于内存不足,虚拟机没有可分配的内存了,垃圾回收器也不能释放更多的内存。程序抛出OutOfMemoryError.

一.模拟内存溢出

  1. @RestController
  2. public class CymController {
  3. @GetMapping("/a")
  4. public String index() {
  5. List<byte[]> aalist = new ArrayList<>();
  6. try {
  7. while (true) {
  8. byte[] bytes = new byte[1024];
  9. aalist.add(bytes);
  10. }
  11. } catch (Error error) {
  12. System.out.println("--------" +error);
  13. }
  14. return "11";
  15. }
  16. @GetMapping("/b")
  17. public String b() {
  18. return "Hello World b";
  19. }
  20. }
  1. 调用”/a”接口,打印 java.lang.OutOfMemoryError: Java heap space 错误,表示内存溢出。如果再”/b”接口,发现正常调用。是因为”aalist”是局部变量,抛出错误后,内存被回收了,程序也就恢复正常。
  2. 如果将 “List aalist = new ArrayList<>()” 设置为成员变量。如果调用”/a”接口,则程序处于假死状态,再调用”/b”接口,一直处于等待。是因为”aalist”一直没发回收掉,程序一直在FullGC.

二.排查

  • 主动导出Dump文件 jmap -dump:format=b,file=文件名
  • 被动导出Dump文件 -XX:+HeapDumpOnOutOfMemoryError
  1. -XX:+HeapDumpOnOutOfMemoryError,从字面就可以很容易的理解,在发生OutOfMemoryError异常时,进行堆的Dump,这样就可以获取异常时的内存快照了。
  2. -XX:HeapDumpPath=D:\heap-dump\ ,这个也很好理解,就是配置HeapDump的路径,方便我们管理,这里我们配置为D:\heap-dump,当然你也可以根据自己的需要,定义为其他的目录。

    注意,HeapDumpPath的目录一定要手动创建好,如果没有这个目录,Dump会失败的。

  3. 通过MAT工具分析,哪些大对象可能存在问题,自己去分析。