Java 学习目录
上一章 JVM 深入理解 - 字符串常量池
本机直接内存溢出
- 设置方法:-XX:MaxDirectMemorySize=size
本机直接内存可以通过上面的参数进行设置(默认与堆内存最大值一样),所以也会出现 OOM 异常。 - 由直接内存导致的内存溢出,一个比较明显的特征是在 HeapDump 文件中不会看见有什么明显的异常情况,如果发生了 OOM,同时 Dump 文件很小,可以考虑重点排查下直接内存方面的原因。
栈溢出
- 设置方法: -Xss1m
注:HotSpot 版本中栈的大小是固定的,是不支持拓展的。 - 明显异常:java.lang.StackOverflowError
- 触发方式: 一般的方法调用是很难出现的,除非方法无限递归。
- 解决办法:
- 查找有无无限递归方法,找到后处理掉。
- 如果是正常情况的话,那就要加大内存。
- 题外话:递归与循环。
由于jvm 设计规则。所以同样的功能使用循环一定比递归要快,因为要不停地打包成栈帧压入栈中。因为要不停地打包成栈帧压入栈中。 - 同时要注意,栈区的空间 JVM 没有办法去限制的,因为 JVM 在运行过程中会有线程不断的运行,没办法限制,所以只限制单个虚拟机栈的大小。
/**
* 栈溢出 -Xss=1m
*/
public class StackOverFlow {
public void dance(int a){//方法不断执行-栈帧不断入栈(不出栈)
System.out.println(a);
dance(++a);//
}
public static void main(String[] args)throws Throwable {
StackOverFlow javaStack = new StackOverFlow();
javaStack.dance(1);
}
}
当调整栈内存大小后会有所改善,但是还是要预防无限递归。
堆溢出
- 设置方法:-Xms;-Xmx;
- 明显异常:java.lang.OutOfMemoryError:java heap space
- 触发方式:
- 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
- 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
- 代码中存在死循环或循环产生过多重复的对象实体;
- 使用的第三方软件中的BUG;
- 启动参数内存值设定的过小;
- 解决办法:
- 检查是否有方法异常创建对象,有引用而不使用。
- 增加内存。
- 适当增加其他引用关系。
/**
* VM Args:-Xms30m -Xmx30m -XX:+PrintGCDetails
* 堆内存溢出(直接溢出)
*/
public class HeapOom {
public static void main(String[] args)
{
String[] strings = new String[35*1000*1000]; //35m的数组(堆)
}
}
方法区溢出
- 运行时常量池溢出
- 方法区中保存的 Class 对象没有被及时回收掉或者 Class 信息占用的内存超过了我们配置。
- 注意 Class 要被回收,条件比较苛刻(仅仅是可以,不代表必然,因为还有一些参数可以进行控制)
- 该类所有的实例都已经被回收,也就是堆中不存在该类的任何实例。
- 加载该类的 ClassLoader 已经被回收。
- 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 方法区导致的内存溢出
* VM Args: -XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M
* */
public class MethodAreaOutOfMemory {
public static void main(String[] args) {
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TestObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object arg0, Method arg1,
Object[] arg2, MethodProxy arg3) throws Throwable {
return arg3.invokeSuper(arg0, arg2);
}
});
enhancer.create();
}
}
public static class TestObject {
private double a = 34.53;
private Integer b = 9999999;
}
}
- -Xnoclassgc 禁用类的垃圾收集(GC)