动手实验:JVM栈内存溢出的时候,应该如何解决?
栈内存溢出能依托之前的办法解决吗?
首先大家思考一个问题:栈内存溢出能按照之前的方法解决吗?
也就是说,GC日志、内存快照,这些东西对解决栈内存溢出有帮助吗?
首先明确一点,栈内存溢出跟堆内存是没有关系的,因为他的本质是一个线程的栈中压入了过多方法调用的栈桢,比如几千次方法调用的几千个栈桢。
此时就导致线程的栈内存不足,无法放入更多栈桢了。
所以GC日志对你有用吗?没用!因为GC日志主要是分析堆内存和Metaspace区域的一些GC情况的,就线程的栈内存和栈桢而言,他们不存在所谓的GC。
如果大家还记得之前我们画的图,就应该知道,调用一个方法时在栈里压入栈桢,接着执行完整个方法,栈桢从栈里出来,然后一个线程运行完毕时,他的栈内存就没了。
所以本身这块内存不存在所谓的GC和回收,调用方法就给栈桢分配内存,执行完方法就回收掉那个栈桢的内存。
那么内存快照呢?
内存快照主要是分析一些内存占用的,同样是针对堆内存和Metaspace的,所以对线程的栈内存而言,也不需要借助这个东西。
示例代码
使用的JVM参数如下:
运行代码后分析异常报错信息的调用栈
接着我们运行代码让他产生栈内存溢出的报错,如下:
实际上我们会在这里看到大段大段的如上所示的异常,也就是说,他会直接告诉你这个栈内存溢出的问题,是因为你拼命的调用Demo2这个类的work()方法时发生的。
因此就栈内存溢出而言,我们定位和解决问题非常的简单,你只要把所有的异常都写入本地日志文件,那么当你发现系统崩溃了,第一步就去日志里定位一下异常信息就知道了。
比如,昨天我们通过异常信息直接定位出来是Metaspace区域出的异常,然后分析一下GC日志就完全知道发生溢出的全过程,接着再分析一下MAT的内存快照,就知道是哪个类太多导致的异常。
今天的栈内存溢出,我们直接去日志文件里看到是栈内存溢出:Exception in thread "main" java.lang.StackOverflowError。
此时心里就有数了,然后直接看一下对应报错的方法就可以了。知道是哪个方法,直接去代码中定位问题即可。