Memory异常

OutOfMemoryError

抛出范围:Java虚拟机规范的描述中,出程序计数器外,虚拟机栈、本地方法栈、堆内存、方法区均可抛出OutOfMemoryError异常。

Java堆溢出:用于存储对象,只要满足不断创建对象,并保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么当对象达到一定数量之后就会抛出堆溢出异常“java.lang.OutOfMemoryError”。

堆溢出解决方式:一般先通过内存映像分析工具对Dump出来的堆转储快照进行分析,重点是确认内存中的对象是否是必要的,也就是分清楚到底是内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。

内存泄漏解决方式:通过工具查看泄漏对象到GC Roots的引用链,找到泄漏对象是通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收它们的。掌握了泄漏对象的类型信息及GC Roots引用链信息就可以比较准确地定位出泄漏代码的位置。

内存溢出解决方式:不存在内存泄漏,即内存中的对象都还必须存活着,那就应当与机器物理内存对比看是否调大虚拟内存的堆参数;从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗

StackOverflowError

抛出范围:虚拟机栈、本地方法栈

抛出情形
①:线程请求栈深度大于虚拟机允许的最大深度,抛出StackOverflowError异常。
②:如果虚拟机在扩展栈时无法申请到足够的内存空间,抛出MemoryOverflowError异常。

特殊特点
①单线程:无论是栈帧太大还是虚拟机栈容量太小,均是抛出StackOverflowError异常
②多线程:通过不断创建线程的方式可以产生内存溢出异常。栈的总内存大小是一个特定值(可利用参数设定),在这种情况下,为每个线程的栈分配的内存越大,反而越容产生内存溢出异常。(原因:操作系统分配给进程的内存空间是有限的,32位win10限定为2GB。虚拟机提供参数来控制Java堆以及方法区这两大内存区域,程序计数器占用小部分内存,剩余内存被Java虚拟机栈、本地方法栈进行瓜分。每个线程分配到的栈容量越大,可建立线程数量越少,建立线程时越容易将内存耗尽)

解决方法:虚拟机默认参数情况下,大多数栈深度可达到1000~2000(每个方法压入栈的帧大小不同),大多数情况够用。但是,如果是建立过多线程导致的内存溢出,再不能减少线程数量和更换64位虚拟机的情况下,就只能通过减少最大堆和减少栈的容量来换取更多的线程。

方法区和运行时常量池溢出

运行时常量池溢出
运行时常量池位于方法区,由于运行时常量池的内容是程序运行过程中动态添加的,因此在运行过程中频繁的添加常量可能会导致运行时常量词溢出(String.intern())。

方法区溢出
方法区用于存放Class的相关信息,如类名、访问修饰符、方法描述、字段描述、常量词等。对于这些区域的测试,基本思路就是运行时产生大量的类区填满方法区,直到溢出。

发布了28 篇原创文章 · 获赞 3 · 访问量 1600

猜你喜欢

转载自blog.csdn.net/qq_43044875/article/details/104166836