StackOverFlow & OutOfMemory
StackOverFlow & OutOfMemory
两者都为 Error,广义上的“异常”
StackOverflow
通常为 Java 虚拟机栈内存不够,JVM 对方法栈只有入栈和出栈的操作,所以在此处要报异常,让方法一直加入到方法栈中,而不出栈,将栈爆满,即可报异常。
举个栗子(最简单的栗子,无限递归)
public class StackErrorTest {
private static int count = 0;
public static void main(String[] args) {
System.out.println(count++);
main(args);
}
}
可以通过增加栈内存来解决部分问题,但不是长久解决方法,还是得优化代码。(-Xss1024m)(不建议设置太大,一般1M即可)栈大小设置
OOM
oom(java.lang.OutOfMemoryError)
Java heap space
和 StackOverflow 类似,JVM 堆空间不足,对象实例及数组几乎都放在堆空间中,所以可以一直加新的对象让堆空间爆满。
举个栗子
import java.util.ArrayList;
import java.util.List;
public class OOMTest {
public static void main(String[] args) {
List<O> list = new ArrayList<>();
while (true){
list.add(new O(1024*1024*1024));
System.out.println(list.size());
}
}
}
class O{
private byte[] bs;
public O(int length){
this.bs = new byte[length];
}
}
同理,可以增加堆空间暂时解决问题 -Xms10240m -Xmx10240m
- -Xms 设置堆空间的初始内存大小 默认为内存 1/64
- -X 是jvm的运行参数
- ms memory start
- -Xmx 设置堆空间最大内存大小 默认为内存 1/4
MetaSpace(jdk8及以上)
属于元空间内存不够,元空间主要存放类信息,在加载过多的类会触发该报错,但在 jdk8 中方法区(8之后叫元空间)采用本地内存,最大值为本地运行内存大小,所以一般不会触发该报错。
修改元空间大小来触发报错
- -XX:MetaspaceSize=10m
- -XX:MaxMetaspaceSize=10m
设置初始大小为 10m,设置最大元空间大小为10m
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class JavaMethodAreaOOM {
public static void main(String[] args) {
while (true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o,objects);
}
});
enhancer.create();
}
}
static class OOMObject{}
}
Direct buffer memory
本地直接内存不足,该内存不使用堆内存,不代表本地直接内存无限大,由于系统内存大小受限,所以本地内存和堆内存总和是有限制的,默认与堆内存大小一致
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
public class OOM2 {
public static void main(String[] args) {
int buffer = 1024 * 1024 * 100; //100M
List<ByteBuffer> list = new ArrayList<>();
int count = 0;
try {
while (true){
ByteBuffer direct = ByteBuffer.allocateDirect(buffer);
list.add(direct);
count++;
}
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println(count);
}
}
}