DengQN·一个普通程序员;
Java内存区块内存溢出
2019-02-11 14:34 59
#溢出#内存#方法#类#区#参数#直接#会

想办法让Jvm的各个分区OOM

堆内存

堆内存溢出主要是一直创建对象,但是又不能被GC回收(可达性分析,GC Root和对象之间有可达路径)就会溢出了。

参数:-Xmx20m -Xms20m -XX:+HeapDumpOnOutOfMemoryError

byte[] a = new byte[21 * 1024 * 1024];

加上HeapDumpOnOutOfMemoryError 可以dump出日志,便于后续分析OOM的问题所在

栈内存溢出

虚拟机栈里有个局部变量表,通过不断创建局部变量,可以让它爆掉

(这里没成功OOM,不懂是Jvm的原因还是什么)

参数: -Xss1m -XX:+HeapDumpOnOutOfMemoryError

public void StackOOM() {
        while (true) {
            Thread thread = new Thread(this::job);
            thread.start();
        }
    }

    private void job() {
        while (true) {
        }

    }

方法区溢出

方法区用于存放类的信息,所以想要溢出方法区,只要动态地生成大量的类就可以了。比较简单地生成类的方法是通过使用Cglib生成。所以说

有使用Cglib的项目是有可能出现方法区溢出异常的,比如Spring的Aop,如果大量的增强类,会产生很多的类,方法区的大小不够就会产生异常。

如果使用-XX:PermSize=1M -XX:MaxPermSize=1M,要确保jvm版本低于8,因为Java1.8移除了永久代,类信息放在了Meta Space。

控制Meta space用 -XX:MetaspaceSize-XX:MaxMetaspaceSize

参数:-XX:MaxMetaspaceSize=10m -XX:MetaspaceSize=10m -Xmx20m -Xms10m

while (true){
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(TestMain.class);
    enhancer.setUseCache(false);
    enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> methodProxy.invokeSuper(o, objects));
    enhancer.create();
}

Exception in thread "main" java.lang.OutOfMemoryError: Metaspace

直接内存溢出

直接内存溢出通常出现在Nio出现的地方,比如Netty。可以通过unsafe方法直接请求系统内存来模拟直接内存溢出。

参数: -XX:MaxDirectMemorySize=10M -XX:+HeapDumpOnOutOfMemoryError

Field field = Unsafe.class.getDeclaredFields()[0];
    field.setAccessible(true);
    Unsafe unsafe = (Unsafe) field.get(null);
    while (true) {
        unsafe.allocateMemory(1 * 1024 * 1024);
}

Exception in thread "main" java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method)