1.Java堆溢出
只要不断地创建对象,并且保证GC roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象数量到达最大堆的容量限制后就会产生内存溢出异常。

要解决这个异常,一般先通过内存映像分析工具对堆转储快照分析,确定内存的对象是否是必要的(即判断是内存泄露还是内存溢出)。

如果是内存泄露,可以进一步通过工具查看泄露对象到GC Roots的引用链,比较准确地定位出泄露代码的位置。

如果是内存溢出,可以调大虚拟机堆参数,或者从代码上检查是否存在某些对象生命周期过长的情况。

2.虚拟机栈和本地方法栈溢出
如果线程请求的栈深度大于虚拟机栈允许的最大深度,将抛出StackOverflowError异常。如果虚拟机在拓展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

定义大量的本地变量,增大此方法帧中本地变量表的长度,达到栈允许的最大深度后,就会抛出StackOverflowError。

单线程情况下,很难抛出OutOfMemoryError异常。因为你在达到栈最大深度时,一般都还没有用完内存空间。

如果是多线程情况下,不断创建新的线程,新的线程中又不断创建新变量,可能会抛出OutOfMemoryError。

3.方法区和运行时常量池溢出
String.intern()是一个native方法,它的作用是:如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象,否则将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。

在JDK1.6及之前的版本中,由于常量池分配在永久代中,如果不断地intern,会抛出OutOfMemoryError异常。使用JDK1.7就不会抛出。

方法区溢出的情况:一个类要被垃圾回收器回收掉,判断条件是比较苛刻的。在经常动态产生大量Class的应用中,需要特别注意类的回收状况。比如动态语言、大量JSP或者动态产生JSP文件的应用(JSP第一次运行时需要编译为Java类)、基于OSGi的应用(即使是同一个类文件,被不同的加载器加载也会视为不同的类)。