OutOfMemoryError OOM 几种异常

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

/**
 * OutOfMemoryError  是error 不是异常;Object-Throwable-error-VirtualMechineError-OutOfMemoryError
 */
public class OOMDemo {

    public static void main(String[] args) {
 Object o = new Object();
        //方法分别单独调用,各个方法调用前 先配置OOMDemo项目的vm参数(idea-run-edit configurations-application:项目vm)
        //stackOverflowError();
        //javaHeapSpace();
        //GCOverhead();
        //directBufferMemory();
        //unableCreateNewThread();
        metaspaceOOM(args);
    }

    /**
     * StackOverflowError:栈溢出
     * 自己调用自己,深度循环调用。
     * Exception in thread "main" java.lang.StackOverflowError
     */

    private static void stackOverflowError() {
        stackOverflowError();
    }

    /**
     * OutOfMemoryError: Java heap space 堆溢出
     * <p>
     * 设置堆内存小一些,new大对象 -Xms10m  -Xmx10m
     * Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
     */

    private static void javaHeapSpace() {
        Byte[] bytes = new Byte[30 * 1024 * 1024];
    }

    /**
     * GC overhead limit exceeded:GC超出极限,GC一直在高速工作。
     * <p>
     * GC回收时间过长抛出OutOfMemoryError。过长的定义:超过98%时间用来做GC并且收回了不到2%的堆内存,连续多次GC只回收了不到2%的极端情况下才会抛出。
     * 加入不抛出,则2%立马会被填满,迫使再次GC,形成恶行循环,CPU一直是100%,而GC没有任何效果。
     * jvm参数配置:-Xms10m  -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
     * [Full GC (Ergonomics) java.lang.OutOfMemoryError: GC overhead limit exceeded
     * [Full GC (Ergonomics) [PSYoungGen: 1024K->1024K(2048K)] [ParOldGen: 7086K->7067K(7168K)] 8110K->8091K(9216K), [Metaspace: 3707K->3707K(1056768K)],
     * <p>
     * <p>
     * String.intern():如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符添加到常量池中,并返回此String对象的引用。
     */
    private static void GCOverhead() {
        int i = 0;
        List<String> list = new ArrayList<>();

        try {
            while (true) {
                list.add(String.valueOf(i++).intern());
            }
        } catch (Throwable e) {
            System.out.println("**********i=" + i);
            e.printStackTrace();
            throw e;
        }
    }

    /**
     * 直接内存溢出:
     * 导致原因:写NIO程序经常使用ByteBuffe来读取和写入数据,这是一种基于通道channel和缓冲区buffer的I/O方式
     * 它可以直接使用Native函数库z直接分配堆外内存,然后通过一个存储在java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。
     * 这样能在一些场景中显著提高性能,因为避免了在java堆和native堆中来回复制数据。
     * <p>
     * ByteBuffer.allocate(capability)第一种方式是分配jvm堆内存,属于GC管辖,由于需要copy所以速度慢
     * ByteBuffer.allocateDirect(capability)第一种方式是分配OS本地内存,不属于GC管辖,不需要内存copy所以很快。
     * <p>
     * 但由于不断分配本地内存,堆内存很少使用,那么JVM就不需要执行GC,DirectByteBuffer对象就不会被回收。
     * 出翔堆内存充足,本地内存耗光。再次分配本地没存就会出现OutOfMemoryError,程序崩溃。
     * <p>
     * DirectMemory:直接内存,指的是物理内存,默认最大时1/4本地内存
     * <p>
     * jvm堆内存:DirectMemory直接内存(1/4本地内存):本地内存
     * <p>
     * 配置参数:-Xms10m  -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
     * <p>
     * 故障现象:Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
     * Full GC (System.gc()) [PSYoungGen: 501K->0K(2560K)] [ParOldGen: 1350K->1612K(7168K)] 1852K->1612K(9728K),
     * [Metaspace: 3425K->3425K(1056768K)] 元空间满了
     */
    private static void directBufferMemory() {

        System.out.println("配置的MaxDirectMemorySize:" + sun.misc.VM.maxDirectMemory() / (double) 1024 / 1024 + "MB");
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 * 1024);
    }

    /**
     * 高并发请求处理器时,经常出现如下异常:
     * native thread异常与对应平台有关。
     * <p>
     * 导致原因:
     * 1 你的应用创建了太多线程,一个应用进程创建太多线程,超过系统极限;
     * 2 服务器并不允许你创建这么多线程,linux默认单个进程最多创建1024个,如果超过就报异常;
     * <p>
     * 解决办法:
     * 1 降低应用进程创建的线程数量,改代码
     * 2 对于有的应用,需要很多线程则修改服务器设置,扩大linux的默认值。
     * 系统调优:
     * 1 ulimit -u   (查看默认多少个)
     * 2 vim /etc/security/limits.d/90-nproc.conf  查看各个用户限制多少个数 root 无上限,可以怎就该用户 或者更改用户的限制数量
     * <p>
     * <p>
     * <p>
     * windows未爆出异常但是 Full GC已经几乎失效
     * [Full GC (Ergonomics) [PSYoungGen: 1023K->1023K(2048K)] [ParOldGen: 7168K->7166K(7168K)] 8191K->8190K(9216K), [Metaspace: 3971K->3971K(1056768K)]
     * <p>
     * LINUX: 默认1024
     * 1 cd /aleneuse/        (java文件所在文件夹)
     * 2 ll        (目录)
     * 3 javac -d . OOMDemo.java         (编译java文件)
     * 4 cat OOMDemo.java           (运行需要带包名,查看包名)
     * 5 java com.founder.rhip.drs.controller.OOMDemo        (运行。包名+类名)
     * 之后会报错:
     * OutOfMemoryError:unable to create new native thread  i<1024
     */
    private static void unableCreateNewThread() {

        for (int i = 0; ; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(Integer.MAX_VALUE);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
            System.out.println("Thread" + i);
        }
    }

    /**
     *
     *OutOfMemoryError: Metaspace 元空间溢出异常
     *
     * jvm参数:-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m
     *
     * 代替永久代
     *
     * Metaspace是方法区在HotSpot中实现,他在本地内存,而不是虚拟机内存,class metadata被存储在Metaspace的native memory
     *
     *永久代:虚拟机加载的类信息;常量池;静态变量;即时编译后的代码
     *
     * 模拟Metaspace溢出,不断生成类放入元空间,类占据的空间超过Metaspace指定的空间大小
     *
     *异常现象:
     * 多少次后发生异常:183
     * java.lang.OutOfMemoryError: Metaspace
     * Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
     *
     */
    private static void metaspaceOOM(String[] args) {
        final String[] arg = args;
        int i = 0;
        try {
            while (true){
                i++;
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(OOMTest.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,arg);
                    }
                });
                enhancer.create();
            }
        } catch (Throwable e) {
            System.out.println("多少次后发生异常:"+i);
            e.printStackTrace();
            throw e;
        }

    }

    static class OOMTest{}; //静态类放在元空间

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值