三、OutOfMemoryError异常
(一)Java堆溢出
-Xms20m 设置堆的初始值,默认情况是机器物理内存的1/64
-Xmx20m 设置堆的最大值,默认是机器物理内存的1/4(-Xms等于-Xmx时,即可避免自动扩展)
Java堆用于存储对象,只要不断的创建对象,并且避免被GC,那么在对象数量到达最大堆的容量限制后就会产生OutOfMemoryError异常。
(二)虚拟机栈和本地方法栈溢出
对于HostSpot来说,虽然-Xoss(设置本地方法栈大小)参数存在,由于HostSpot将本地方法栈放入虚拟机栈中实现的,所以-Xoss是无效的,栈容量只由-Xss参数来设定。
在单个线程下,无论是由于栈帧太大还是虚拟机容量太小,当内存无法分配的时候,虚拟机抛出的都是StackOverflowError异常。通过不断的创建线程,加大为每个线程分配的内存,可导致OutOfMemoryError异常。
(三)方法区和运行时常量池溢出
-XX:PermSize=10M
-XX:MaxPermSize=10M(JDK8移除了持久代,所以PermSize被弃用了,多了一个元数据区,设置元数据区的参数为MetaSpaceSize)
只要不停的向字符串常量池中放入字符串就可导致OutOfMemoryError异常。
JDK6中String.intern()方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中这个字符串实例的引用。JDK7以后String.intern()方法不会再复制实例,只是在常量池中记录首次出现的实例引用。
(四)直接内存溢出
直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。在JDK4中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。避免了在Java堆和Native堆中来回复制数据。
直接内存大小可由-XX:MaxDirectMemorySize指定,如果不指定,则默认与Java堆最大值一样。由Direct Memory导致的内存溢出,一个明显的特征是在Head Dump文件中不会看见明显的异常,如果读者发现OOM之后Dump文件很小,而程序中又直接或间接使用了NIO,那就可以考虑一下是否是由于Direct Memory导致的。