banner
RustyNail

RustyNail

coder. 【blog】https://rustynail.me 【nostr】wss://ts.relays.world/ wss://relays.world/nostr

Java内存区块内存溢出

想办法让 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=10m -XX=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=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)

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.