深入理解JVM学习笔记(三)
一、OutOfMemoryError
1.Java堆溢出
Java堆用于存储对象实例,只要不断地实例对象,并避免GC将他们回收,那么在对象达到最大堆容量的时候就会产生内存溢出错误。
这里介绍几个关于关于堆的参数:
-Xms:堆的最小值 -Xmx:堆的最大值 -Xmn:新生代的大小 -XX:+HeapDumpOnOutOfMemoryError:让虚拟机在出现内训溢出错误的时候Dump出当前的内存堆转存快照
这个区域出现OOM要先确定是内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。
如果是内存泄漏,找到泄漏对象是通过怎样的路径与GC Roots关联并导致垃圾收集器无法回收他们,从而准确定位到泄漏代码的位置。
如果不存在泄漏,应当检查虚拟机堆参数,与机器物理内存对比看是否还有调大的空间,从代码上检查是否有存在生命周期过长,持有时间过长的情况,尝试减少程序运行期的内存消耗。
2.虚拟机栈和本地方法栈溢出
HotSpot虚拟机不区分本地方法栈和虚拟机栈,所以栈容量统一使用-
Xss参数来设定。
虚拟机栈异常分为两种情况:
- 当线程所申请的栈深度大于虚拟机提供的最大栈深度,就会抛出StackOverflowError
- 当虚拟机在扩展栈时无法申请到足够的空间,就会抛出OutOfMemoryError
在单线程情况下,无论是由于栈帧太大还是虚拟机栈容量太小,当内存无法分配时,都只会抛出StackOverflowError。因为只有一个线程时,也就是只有一个栈,虚拟机栈容量太小的时候放不下太多的东西,自然是StackOverflowError,而栈帧太大的时候更不用说,虚拟机栈容不下那么大的栈帧,自然也是StackOverflowError。
但是在多线程情况下,通过不断地建立线程的方式可以产生内存不足异常,但这不是因为栈内存不足,相反,为每个线程分配的空间越大反而越容易内存不足。
其实这很好理解,因为虚拟机栈时线程私有的,没有一个线程就会有一个栈,内存一共就那么大,每一个线程的内存大了,那线程数不就越少吗,同样建立线程的时候更容易内存不足。所以在多线程情况下导致的内存溢出,一般是通过减少最大堆和减少栈容量来换取更多的线程。
3.方法区溢出
方法区溢出也是一种常见的内存溢出异常,一个类要被垃圾收集器回收点的条件比较苛刻。在经常动态生成大量Class的应用中,需特别注意类的回收状况
可以通过
-XX:PermSize和
-XX:MaxPermSize限制方法区的大小
4.本机直接内存溢出
直接内存的容量可以通过
-XX:MaxDirectMemorySize指定,如果不指定,则默认与Java堆最大值(-Xmx指定)一样。
直接通过反射获取Unsafe实例进行内存分配,这样是直接向操作系统申请分配内存,从而达到本地直接内存溢出。
- 【深入理解JVM】学习笔记——-1、JVM基本结构
- 深入理解JVM虚拟机学习笔记(四)虚拟机性能监控和故障处理工具
- 深入理解JVM学习笔记——第十三章 线程安全与锁优化
- 深入理解jvm学习笔记1
- 深入理解JVM学习笔记:第2章 Java内存区域与内存溢出异常
- 深入理解JVM虚拟机学习笔记(三)内存分配和回收策略
- 深入理解JVM——第四章 JVM执行子程序学习笔记
- 深入理解JVM虚拟机学习笔记(二)垃圾收集器与垃圾收集算法
- 【Java】深入理解JVM学习笔记(一) —— JVM数据区域
- 《深入理解 Java 虚拟机》学习笔记(1)—— JVM 运行时数据区
- 深入理解JVM 学习笔记2
- 【Java】深入理解JVM学习笔记(三) —— GC收集器和内存分配
- 深入理解JVM虚拟机学习笔记(—)内存区域与内存溢出异常
- 深入理解JVM学习笔记-垃圾收集器和内存分配策略
- 深入理解JVM学习笔记-自动内存管理机制
- 深入理解JVM学习笔记:第3章 垃圾收集器与内存分配策略
- 《深入理解 Java 虚拟机》学习笔记(1)—— JVM 运行时数据区
- 深入理解JVM——第五章、JVM性能优化学习笔记
- 《深入理解 Java 虚拟机》学习笔记(1)—— JVM 运行时数据区
- 深入理解JVM--我的学习笔记