深入理解JVM——实战:outofmemoryerror异常
目的:
1.通过代码验证Java虚拟机规范中描述的各个运行时区域存储的内容。
2.遇到实际的内存溢出异常时,能根据异常的信息快速判断是哪个区域的内存溢出,知道什么样的代码可能会导致这些区域内存溢出,以及出现这些异常后该如何处理。
Java堆溢出
Java堆用于存储对象实例,只要不断地创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象数量到达最大堆的容量限制后就会产生内存溢出异常。
当出现Java堆内存溢出时,异常堆栈信息“java.lang.OutOfMemoryError”会跟着进一步提示“Java heap space”。要解决这个区域的异常的思路是:通过内存映像分析工具(如Eclipse Memory Analyzer)对Dump出来的堆转储快照进行分析,重点是确认内存中的对象是否是必要的,即先分清楚到底是内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots的引用链,找到泄漏对象是通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收它们的。如果不是内存泄漏,换句话说,就是内存中的对象确实都还必须存活着,那就应当检查虚拟机的堆参数(-Xmx与-Xms),与机器物理内存对比看是否还可以调大,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。
虚拟机栈和本地方法栈溢出
两种异常:
- 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常
- 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。
为每个线程的栈分配的内存越大,反而越容易产生内存溢出异常。
如果是建立过多线程导致的内存溢出,在不能减少线程数或者更换64位虚拟机的情况下,就只能通过减少最大堆和栈容量来换取更多的线程。
方法区和运行时常量池溢出
String.intern()是一个Native方法,它的作用是:如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象。否则,将此String对象包含的字符串添加到常量池中,并返回此String对象的引用。
运行时常量池溢出,在OutOfMemoryError后面跟随的提示信息是“PermGen space”
本机直接内存溢出
真正申请分配内存的方法是unsafe.allocateMemory()
posted on 2018-04-07 15:41 Joyce&wang 阅读(149) 评论(0) 收藏 举报
浙公网安备 33010602011771号