深入理解JVM学习笔记(三)

一、OutOfMemoryError

1.Java堆溢出

  Java堆用于存储对象实例,只要不断地实例对象,并避免GC将他们回收,那么在对象达到最大堆容量的时候就会产生内存溢出错误。

这里介绍几个关于关于堆的参数:

  -Xms:堆的最小值
  -Xmx:堆的最大值
  -Xmn:新生代的大小
  -XX:+HeapDumpOnOutOfMemoryError:让虚拟机在出现内训溢出错误的时候Dump出当前的内存堆转存快照

  这个区域出现OOM要先确定是内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。

  如果是内存泄漏,找到泄漏对象是通过怎样的路径与GC Roots关联并导致垃圾收集器无法回收他们,从而准确定位到泄漏代码的位置。

  如果不存在泄漏,应当检查虚拟机堆参数,与机器物理内存对比看是否还有调大的空间,从代码上检查是否有存在生命周期过长,持有时间过长的情况,尝试减少程序运行期的内存消耗。

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

  HotSpot虚拟机不区分本地方法栈和虚拟机栈,所以栈容量统一使用-Xss参数来设定。

  虚拟机栈异常分为两种情况:

  1. 当线程所申请的栈深度大于虚拟机提供的最大栈深度,就会抛出StackOverflowError
  2. 当虚拟机在扩展栈时无法申请到足够的空间,就会抛出OutOfMemoryError

  在单线程情况下,无论是由于栈帧太大还是虚拟机栈容量太小,当内存无法分配时,都只会抛出StackOverflowError。因为只有一个线程时,也就是只有一个栈,虚拟机栈容量太小的时候放不下太多的东西,自然是StackOverflowError,而栈帧太大的时候更不用说,虚拟机栈容不下那么大的栈帧,自然也是StackOverflowError。

  但是在多线程情况下,通过不断地建立线程的方式可以产生内存不足异常,但这不是因为栈内存不足,相反,为每个线程分配的空间越大反而越容易内存不足。

  其实这很好理解,因为虚拟机栈时线程私有的,没有一个线程就会有一个栈,内存一共就那么大,每一个线程的内存大了,那线程数不就越少吗,同样建立线程的时候更容易内存不足。所以在多线程情况下导致的内存溢出,一般是通过减少最大堆和减少栈容量来换取更多的线程。

3.方法区溢出

  方法区溢出也是一种常见的内存溢出异常,一个类要被垃圾收集器回收点的条件比较苛刻。在经常动态生成大量Class的应用中,需特别注意类的回收状况

可以通过-XX:PermSize-XX:MaxPermSize限制方法区的大小

4.本机直接内存溢出

  直接内存的容量可以通过-XX:MaxDirectMemorySize指定,如果不指定,则默认与Java堆最大值(-Xmx指定)一样。

  直接通过反射获取Unsafe实例进行内存分配,这样是直接向操作系统申请分配内存,从而达到本地直接内存溢出。

你可能感兴趣的:(JVM,JVM)