一、Java堆溢出

测试代码:

/**
* <p>Java堆异常测试</p>
* <code>VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=E:\job</code>
* <p>以上参数的含义是:限制Java堆大小为20MB,不可扩展</p>
* <p>通过此参数可以让虚拟机在出现内存溢出异常时Dump出当前的内存堆转储快照</p>
* <p>将内存溢出快照存储到指定路径:E:\job</p>
*/
public class HeapOOM { static class OOMObject {} public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
while(true) {
list.add(new OOMObject());
}
}
}

执行结果:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to E:\job ...
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2245)
at java.util.Arrays.copyOf(Arrays.java:2219)
at java.util.ArrayList.grow(ArrayList.java:242)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)
at java.util.ArrayList.add(ArrayList.java:440)
at com.sandy.jvm.chapter02.HeapOOM.main(HeapOOM.java:19)

针对这类异常,可通过分析工具(如Eclipse Memory Analyzer)对异常快照进行分析,找到具体发生异常代码。

二、虚拟机栈和本地方法栈的溢出

由于HotSpot虚拟机不区分虚拟机栈和本地方法栈,因此不需要设置-Xoss参数,栈容量只由-Xss参数设定。

针对栈,虚拟机规范了两种异常:

  • 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。

测试代码:

/**
* VM Args: -Xss128k
*/
public class JavaStackSOF { private int stackLength = 1; public void stackLeak() {
stackLength++;
stackLeak();
} public static void main(String[] args) {
JavaStackSOF oom = new JavaStackSOF();
try{
oom.stackLeak();
}catch(Throwable e) {
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}

执行结果:

stack length:2101
Exception in thread "main" java.lang.StackOverflowError
at com.sandy.jvm.chapter02.JavaStackSOF.stackLeak(JavaStackSOF.java:13)
at com.sandy.jvm.chapter02.JavaStackSOF.stackLeak(JavaStackSOF.java:14)
at com.sandy.jvm.chapter02.JavaStackSOF.stackLeak(JavaStackSOF.java:14)
at com.sandy.jvm.chapter02.JavaStackSOF.stackLeak(JavaStackSOF.java:14)
at com.sandy.jvm.chapter02.JavaStackSOF.stackLeak(JavaStackSOF.java:14)
at com.sandy.jvm.chapter02.JavaStackSOF.stackLeak(JavaStackSOF.java:14)
at com.sandy.jvm.chapter02.JavaStackSOF.stackLeak(JavaStackSOF.java:14)
...

单个线程下,无论是由于栈帧太大还是虚拟机栈容量太小,虚拟机抛出的都是StackOverflowError。

  • 如果虚拟机扩展栈时,无法申请到足够的空间,将抛出OutOfMemoryError异常。

测试代码:

/**
* VM Args: -Xss2M (这时候不妨设置大一点点)
*/
public class JavaStackOOM {
private void dontstop() {
while(true) { }
} public void stackLeakThread() {
while(true) {
new Thread() {
@Override
public void run() {
dontstop();
}
}.start();
}
} public static void main(String[] args) {
JavaStackOOM oom = new JavaStackOOM();
oom.stackLeakThread();
}
}

测试结果会抛出:Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread

这种情况下,为每个线程栈分配的内存越大,越容易出现内存溢出。

原因是:操作系统为每个进程分配的内存有限制,比如32位windows限制为2GB,栈内存=2GB-Xmx(最大堆容量)-MaxPermSize(最大方法区容量),每个线程分配的栈内存越大,可创建的线程数就越少,越容易把剩下内存耗尽。

三、方法区和常量池溢出

String.intern()是一个Native方法,作用是:如果字符串常量池已包含了一个等于String对象的字符串,则返回这个字符串的String对象,否则,将此String对象包含的字符串添加到常量池,并且返回此String对象的引用。

在jdk1.6及之前版本,常量池分配在永久代中,可通过-XX:PermSize和-XX:MaxPermSize限制方法区大小。

/*
* VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M(限制常量池容量)
*
*/
public class RunTimeConstantPoolOutOfMemoryError { public static void main(String[] args) {
// 使用list保持常量池引用,避免常量池内的数据被垃圾回收清除
List<String> list = new ArrayList<>();
long i = 0;
while (true) {
String string = (i++) + "";
list.add(string.intern());
}
}
}

此段代码在jdk6之前的版本中运行时会产生:Exception in thread "main" java.lang.OutOfMemoryError: PermGen space 其中PermGen space指示内存溢出发生在运行时常量池中。

在jdk7的环境中运行得到的结果却是: Exception in thread "main" java.lang.OutOfMemoryError: Java heap space  指示内存溢出发生在堆中而不是方法区中的常量池。

因为在 JDK1.2 ~ JDK6 的实现中,HotSpot 使用永久代实现方法区,而从 JDK7 开始 Oracle HotSpot 开始移除永久代,JDK7中符号表被移动到 Native Heap中,字符串常量和类引用被移动到 Java Heap中。在 JDK8 中,永久代已完全被元空间(Meatspace)所取代。

四、本机直接内存溢出

DirectMemory容量可通过-XX:MaxDirectMemorySize指定,如果不指定,默认与Java堆最大值一样。

测试代码:

/**
* VM Args: -Xmx20M -XX:MaxDirectMemorySize=10M
*/
public class DirectMemoryOOM { private static final int _1MB = 1024*1024; public static void main(String[] args) throws Exception {
Field unsafeFiled = Unsafe.class.getDeclaredFields()[0];
unsafeFiled.setAccessible(true);
Unsafe unsafe = (Unsafe)unsafeFiled.get(null);
while(true) {
unsafe.allocateMemory(_1MB);
}
}
}

测试结果:

Exception in thread "main" java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)
at com.sandy.jvm.chapter02.DirectMemoryOOM.main(DirectMemoryOOM.java:22)

由DirectMemory导致的内存溢出,明显特征是在Heap Dump文件中不会看见明显的异常,如果发现Dump文件很小,而程序直接或间接使用了NIO,那可以考虑是否由此原因引起。

最新文章

  1. 基于modelsim-SE的简单仿真流程—下
  2. Python 逐行修改txt每条记录的内容
  3. [Python]读写文件方法
  4. 开源的Android开发框架-------PowerFramework使用心得(二)图片异步加载ImageTask
  5. Android 自定义日历
  6. realloc,c语言
  7. qt+boost::asio+tcp文件传输
  8. C语言之原码、反码和补码
  9. 实现兼容document.querySelector的方法
  10. Tomcat7配置Https
  11. Django Models的数据类型汇总
  12. docker 支持ipv6 (核心要点是ndp需要把docker内的ip全部加入到ndplist中来)
  13. Ex 5_22 在此我们基于以下性质给出一个新的最小生成树算法..._第九次作业
  14. Android 支付宝/微信支付结果判断
  15. C#字符串长度判断
  16. oracle 绝对值小于1的数值显示小数点前面的0
  17. C语言中函数和指针的參数传递
  18. 使用tornado实现用户认证
  19. 用nw.js开发markdown编辑器-已完成功能介绍
  20. Linux中apache服务

热门文章

  1. Java 并发 —— Java 标准库对并发的支持及 java.util.concurrent 包
  2. AtCoder Beginner Contest 104
  3. Cache系列:spring-cache简单三步快速应用ehcache3.x-jcache缓存(spring4.x)
  4. Scala学习——类,继承,接口(中)
  5. iOS端IM开发从入门到填坑
  6. 你所不知道的html5与html中的那些事(三)
  7. Unity查找Editor下Project视图中特定的资源
  8. sorted matrix - search &amp; find-k-th
  9. pysam操作sam文件
  10. Elasticsearch检索分类详解