1.JAVA堆溢出
Java用于存储对象实例,不断创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在对象数量到达最大堆的容量限制后产生内存溢出异常。
内存泄漏(Memory Leak):一部分内存空间已经使用了,却没有引用指向这部分空间。造成这片已经使用的空间无法处理。
2.虚拟机栈和本地方法栈溢出
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。
在单个线程下,无论时栈帧太大,还是虚拟机栈容量太小,当内存无法分配的时候,虚拟机抛出的都是StackOverflowError异常。
在多线程下,不断地建立线程会长生内存溢出异常。给每个线程的栈分配的内存越大,反而越容易产生内存溢出异常。原因如下:
操作系统分配给每个进程的内存是有限的,比如32位的Windows限制为2GB,虚拟机提供了参数来控制Java堆和方法区的这两部分内存的最大值,不考虑虚拟机本身消耗的内存的情况下,剩余的内存为:
2GB(操作系统限制)-Xmx(最大堆容量)- MPS(MaxPermSize最大方法区容量)-程序计数器消耗的内存(很小,可以忽略)
剩下的就是虚拟机栈和本地方法所占的内存。如果每个线程分配的栈容量越大,可以建立的线程数量就越少,建立线程时就越容易把剩下的内存耗尽。
一般情况下,每个方法压入栈的帧大小并不是一样的,如果建立了过多线程导致的内存溢出,在不能减少线程数或者更换64位虚拟机的情况下,就只能通过减少最大堆和减少栈容量来换取更多的线程。
3.方法区溢出
方法区用来存放Class的相关信息,如类名、访问修饰符、常量池、字段描述等。用-XX:PermSize和-XX:MaxPermSize限制方法区的大小。
(1)运行时常量池溢出。
(2)方法区溢出。
4.本机直接内存溢出
-XX:MaxDirectMemorySize指定本机直接内存大小,如果不指定,则默认和Java堆的最大值(Xmx指定)一样。



