《深入理解java虚拟机》笔记 OutOfMemoryError异常

Java堆溢出

 -Xms    -Xmx    
-XX: +HeapDumpOnOutOf-MemoryError可以让虚拟机在出现内存溢出异常的时候Dump出当前的内存堆转储快照以便进行事后分析

 首先通过内存映像分析工具(如Eclipse MemoryAnalyzer) 对Dump出来的堆转储快照进行分析。 第一步首先应确认内存中导致OOM的对象是否是必要的, 也就是要先分清楚到底是出现了内存泄漏(Memory Leak) 还是内存溢出(Memory Overflow) 。

虚拟机栈和本地方法栈溢出

 HotSpot虚拟机中并不区分虚拟机栈和本地方法栈, 因此对于HotSpot来说, -Xoss参数(设置本地方法栈大小) 虽然存在, 但实际上是没有任何效果的, 栈容量只能由-Xss参数来设定。

1) 如果线程请求的栈深度大于虚拟机所允许的最大深度, 将抛出StackOverflowError异常。
2) 如果虚拟机的栈内存允许动态扩展, 当扩展栈容量无法申请到足够的内存时, 将抛出OutOfMemoryError异常。

·使用-Xss参数减少栈内存容量。
结果: 抛出StackOverflowError异常, 异常出现时输出的堆栈深度相应缩小。
·定义了大量的本地变量, 增大此方法帧中本地变量表的长度。
结果: 抛出StackOverflowError异常, 异常出现时输出的堆栈深度相应缩小。

 无论是由于栈帧太大还是虚拟机栈容量太小, 当新的栈帧内存无法分配的时候,HotSpot虚拟机抛出的都是StackOverflowError异常。

 为每个线程分配到的栈内存越大, 可以建立的线程数量自然就越少, 建立线程时就越容易把剩下的内存耗尽

 

 

如果是建立过多线程导致的内存溢出, 在不能减少线程数量或者更换64位虚拟机的情况下, 就只能通过减少最大堆和减少栈容量来换取更多的线程。

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

 运行时常量池是方法区的一部分。JDK 8中完全使用元空间来代替永久代。

String::intern()是一个本地方法, 它的作用是如果字符串常量池中已经包含一个等于此String对象的字符串, 则返回代表池中这个字符串的String对象的引用; 否则, 会将此String对象包含的字符串添加到常量池中, 并且返回此String对象的引用。

在JDK 6或更早之前的HotSpot虚拟机中, 常量池都是分配在永久代中, 我们可以通过-XX: PermSize和-XX: MaxPermSize限制永久代的大小, 即可间接限制其中常量池的容量。

 用JDK 7或更高版本的JDK来运行这段程序并不会得到相同的结果,自JDK 7起, 原本存放在永久代的字符串常量池被移至Java堆之中。

 一个类如果要被垃圾收集器回收, 要达成的条件是比较苛刻的。

在JDK 8以后, 永久代便完全退出了历史舞台, 元空间作为其替代者登场。

-XX: MaxMetaspaceSize: 设置元空间最大值, 默认是-1, 即不限制, 或者说只受限于本地内存大小。
-XX: MetaspaceSize: 指定元空间的初始空间大小, 以字节为单位, 达到该值就会触发垃圾收集进行类型卸载, 同时收集会对该值进行调整: 如果释放了大量的空间, 就适当降低该值; 如果释放了很少的空间, 那么在不超过-XX: MaxMetaspaceSize(如果设置了的话) 的情况下, 适当提高该值。
-XX: MinMetaspaceFreeRatio: 作用是在垃圾收集之后控制最小的元空间剩余容量的百分比, 可减少因为元空间不足导致的垃圾收集的频率。 类似的还有-XX: Max-MetaspaceFreeRatio, 用于控制最大的元空间剩余容量的百分比。

 本机直接内存溢出

直接内存(Direct Memory) 的容量大小可通过-XX: MaxDirectMemorySize参数来指定, 如果不去指定, 则默认与Java堆最大值(由-Xmx指定) 一致。

虽然使用DirectByteBuffer分配内存也会抛出内存溢出异常, 但它抛出异常时并没有真正向操作系统申请分配内存, 而是通过计算得知内存无法分配就会在代码里手动抛出溢出异常, 真正申请分配内存的方法是Unsafe::allocateMemory()。

直接内存导致的内存溢出, 一个明显的特征是在Heap Dump文件中不会看见有什么明显的异常情况, 如果读者发现内存溢出之后产生的Dump文件很小, 而程序中又直接或间接使用了DirectMemory(典型的间接使用就是NIO)。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值