Java堆溢出
堆内存储对象实例,因此只要不断创建对象,并且保证GC Roots到对象之间有可达路径以免垃圾回收机制清除对象。
/**
* @author: wayne
* @desc:
* @date: 2018/5/10 14:47
* @version: 1.0
* -Xms20M
* -Xmx20M
* -Xmn10M
* -XX:+HeapDumpOnOutOfMemoryError
* -XX:HeapDumpPath=/dump/
*/
public class TestOom {
public static void main(String[] args) throws Exception {
List<TestOom> list = new ArrayList<TestOom>();
while (true){
list.add(new TestOom());
}
}
}
输出结果:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to /dump/\java_pid7088.hprof ...
Exception in thread "main" Heap dump file created [28239072 bytes in 0.117 secs]
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:213)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:187)
at java.util.ArrayList.add(ArrayList.java:411)
at TestOom.main(TestOom.java:17)
Process finished with exit code 1
至于生成的这个文件怎么去解析,后续会有文章跟进,本篇不去关注。堆的异常会生成下面明显的报错:
java.lang.OutOfMemoryError: Java heap space
分析过程简单概括:
首先需要分析出是内存泄漏还是内存溢出
1. 内存泄漏(Memory Leak):程序在申请内存后无法释放已使用的空间,累积会导致最终的内存溢出。
查找过程需要利用工具查看泄漏对象到GC Roots的引用链,定位出为什么具体路径,根据路径查找准确的代码位置。
2. 内存溢出(Memory Overflow):程序在申请内存时没有足够的空间供其使用。
首先看能不能提高虚拟机参数。其次检查代码中哪些对象生命周期过长,尝试减少这些消耗。
Java栈溢出
/**
* @author: wayne
* @desc:
* @date: 2018/5/10 14:47
* @version: 1.0
* -Xss128K
*/
public class TestOom {
private int i = 1;
public void add(){
i++;
add();
}
public static void main(String[] args) throws Exception {
TestOom oom = new TestOom();
oom.add();
}
}
输出结果:
Exception in thread "main" java.lang.StackOverflowError
at TestOom.add(TestOom.java:19)
at TestOom.add(TestOom.java:20)
at TestOom.add(TestOom.java:20)
at TestOom.add(TestOom.java:20)
StackOverflowError的理解:栈的深度超过了JVM分配给线程的栈的大小时会出现。
/**
* @author: wayne
* @desc:
* @date: 2018/5/10 14:47
* @version: 1.0
* -Xss128K
*/
public class TestOom {
private void dos(){
while (true){
}
}
public void add(){
while (true){
Thread t = new Thread(new Runnable() {
public void run() {
dos();
}
});
t.start();
}
}
public static void main(String[] args) throws Exception {
TestOom oom = new TestOom();
oom.add();
}
}
输出结果:
机器卡死了,毛线没看到,慎执行。但是最终结果肯定是
java.lang.OutOdMemoryError: unable to create native thread。
OutOdMemoryError的理解:JVM在扩展栈时无法申请到足够的空间。
方法区和运行时常量池溢出
/**
* @author: wayne
* @desc:
* @date: 2018/5/10 14:47
* @version: 1.0
* -Xms20M
-Xmx20M
-Xmn10M
-XX:PermSize=10M
-XX:MaxPermSize=10M
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/dump/
*/
public class TestOom {
public static void main(final String[] args) throws Exception {
while (true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Oom.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o,args);
}
});
enhancer.create();
}
}
static class Oom{
}
}
输出结果:
java.lang.OutOfMemoryError: PermGen space
Dumping heap to /dump/\java_pid3364.hprof ...
Heap dump file created [3331973 bytes in 0.089 secs]
Exception in thread "main"
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"
方法区存放类的的信息。这些类被回收的条件非常苛刻,因此在大量生产Class的应用中需要注意。
常量池溢出的例子不太好造出来。因为每个版本的常量池放的地方不一样,本例子中使用的都是1.7,报错都是堆内存溢出。