1.Java堆溢出
代码如下:
import java.util.ArrayList;
import java.util.List;
/*
* @author zzf
* @date 2019年3月6日 下午2:48:03
*/
public class HeapOOM {
static class OOMObject{}
public static void main(String[] args) {
List<OOMObject> list=new ArrayList<OOMObject>();
int i=0;
while(true){
System.out.println(i++);
list.add(new OOMObject());
}
}
}
设置Java堆大小为20M(通过设置堆最小值-Xms参数与最大值-Xmx参数设置相同防止堆自动扩展),设置参数-XX:+HeapDumpOnOutOfMemoryError可以让虚拟机在出现内存溢出溢出是Dump当前内存堆转储快照。
-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
分析软件下载地址:http://www.eclipse.org/mat/downloads.php
Java堆内存的OOM异常时常见的内存溢出异常情况,当出现Java堆内存溢出时,异常堆栈信息“java.lang.OutOfMemoryError”会进一步提示“Java heap space”。
解决这个异常主要区分时内存泄漏还是内存溢出。如果是内存泄漏可以看泄漏对象到GC Roots的引用链,最后找到为何垃圾收集器无法自动回收。如果不存在泄漏,这意味着对象都存活,这就检查虚拟机的堆参数(-Xmx和-Xms)。
2.虚拟机栈和本地方法栈溢出
由于在HotSpot虚拟机中不区分虚拟机栈和本地方法栈,所以对于HotSpot来说-Xoss参数(设置本地方法栈大小)是无效的,栈容量只由参数-Xss参数设定。
它在Java虚拟机规范中描述了两种异常:
- 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
- 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。
出现 StackOverflowError的方式:
通过-Xss参数减少栈内存。结果:抛出StackOverflowError异常。
定义大量本地变量,增大方法栈中本地变量表的长度。结果:StackOverflowError异常。
/*
* @author zzf
* @date 2019年3月6日 下午3:47:21
*/
public class JavaVmStackSOF {
private int stackLength;
public void stackLeak() {
stackLength++;
// while(1!=2)
stackLeak();
}
public static void main(String[] args) throws Throwable {
JavaVmStackSOF oom = new JavaVmStackSOF();
try {
oom.stackLeak();
} catch (Throwable e) {
System.out.println(oom.stackLength);
throw e;
// TODO: handle exception
}
}
}
-Xss128k
创建线程导致内存溢出异常:
/*
* @author zzf
* @date 2019年3月6日 下午4:12:15
*/
public class JavaVMStackOOM {
private void dontStop() {
while (true)
;
}
public void stackLeakByThread() {
while (true) {
Thread thread = new Thread(new Runnable() {
public void run() {
dontStop();
}
});
thread.start();
}
}
public static void main(String[] args) throws Throwable {
JavaVMStackOOM oom = new JavaVMStackOOM();
oom.stackLeakByThread();
}
}
注意这段代码会使系统卡死!!!!!!!亲测
1.8以后去除了方法区,而元空间在本地内存中所以不受-XX:PermSize和-XX:MaxPermSize的限制。
3.元空间内存溢出
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/*
* @author zzf
* @date 2019年3月6日 下午5:23:25
*/
public class JavaMethodAreaOOM {
static class OOMObject{
}
static int i=0;
public static void main(String[] args) {
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
System.out.println(i++);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return proxy.invoke(obj, args);
}
});
enhancer.create();
}
}
}
-XX:MetaspaceSize=1M -XX:MaxMetaspaceSize=100M
元空间大小可以通过-XX:MetaspaceSize=XXM和-XX:MaxMetaspaceSize=XXM设置。
4.直接内存溢出
import java.lang.reflect.Field;
/*
* @author zzf
* @date 2019年3月6日 下午4:45:31
*/
public class RuntimeConstantPoolOOM {
// -XX:MaxMetaspaceSize=1M -XX:MaxMetaspaceSize=3M
public static void main(String[] args) {
int i = 0;
try {
Field field = sun.misc.Unsafe.class.getDeclaredFields()[0];
field.setAccessible(true);
sun.misc.Unsafe unsafe = (sun.misc.Unsafe) field.get(null);
while (true) {
unsafe.allocateMemory(1024 * 1024);
i++;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("分配次数:" + i);
}
}
}
-XX:MaxDirectMemorySize=3M
由DirectMemory导致的内存溢出,其特征就是在Heap Dump文件中不会有明显的异常。
参考《深入理解Java虚拟机 JVM高级特性与最佳实践》