zoukankan      html  css  js  c++  java
  • Java-JVM OutOfMemory 情况(JDK8)

    JVM 运行时内存结构(Run-Time Data Areas)

    内存溢出分为两大类:OutOfMemoryError 和 StackOverflowError。

    一、HeapOomError (JVM 堆内存溢出)

    -Xms:初始值
    -Xmx:最大值
    -Xmn:最小值

    public static void main(String[] args) {
        List<byte[]> list = new ArrayList<>();
        int i = 0;
        while (true) {
            list.add(new byte[8 * 1024 * 1024]);
            System.out.println(++i);
        }
    }

    二、MemoryLeakOomError(JVM 堆内存泄漏)

    Java 语言中是指,未使用的对象仍然在 JVM 堆空间中存在,任保留着引用,无法被 GC。不停的堆积最终触发堆内存溢出。

    三、OverheadLimitOomError(垃圾回收超时内存溢出)

    # JDK6 新增错误类型。当 GC 为释放很小空间占用大量时间时抛出。
    # (超过 98% 以上的时间去释放小于 2% 的堆空间)
    java.lang.OutOfMemoryError: GC overhead limit exceeded
    
    # 关闭上述检查功能,通常不治本,最终会 Java heap space。应查看系统是否有使用大内存的代码或死循环
    -XX:-UseGCOverheadLimit

    static class Key {
        Integer id;
        Key(Integer id) {
            this.id = id;
        }
        // @Override
        // public int hashCode() {
        //     return id.hashCode();
        // }
        //
        // @Override
        // public boolean equals(Object o) {
        //     boolean response = false;
        //     if (o instanceof Key) {
        //         response = (((Key) o).id).equals(this.id);
        //     }
        //     return response;
        // }
    }
    
    public static void main(String[] args) {
        Map<Key, String> m = new HashMap<>();
        int x = 0;
        while (true) {
            for (int i = 0; i < 500; i++) {
                if (!m.containsKey(new Key(i))) {
                    m.put(new Key(i), "Number:" + i);
                }
            }
            System.out.println(x++);
        }
    }

    public static void main(String[] args) {
        Map map = System.getProperties();
        Random r = new Random();
        while (true) {
            map.put(r.nextInt(), "Oracle Java");
        }
    }

    四、MetaSpaceOomError(Metaspace内存溢出)

    元空间的溢出,系统会抛出 java.lang.OutOfMemoryError: Metaspace。出现该错误的原因是类非常多或引用的 jar 包非常多或者通过动态代码生成类加载等方法,导致元空间的内存占用很大。

    JDK8 开始,方法区的实现由永久代(PermGen)变成了元空间(Metaspace)。Metaspace 使用的是本地内存,而不是堆内存,也就是说在默认情况下 Metaspace 的大小只与本地内存大小有关。

    # 初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整
    # 如果释放了大量的空间,就适当降低该值。
    # 如果释放了很少的空间,那么在不超过 MaxMetaspaceSize 下适当提高该值。
    -XX:MetaspaceSize
    
    # 最大空间,默认没有限制。
    # 防止因为某些情况导致 Metaspace 无限的使用本地内存,影响到其他程序。应设置大小。
    -XX:MaxMetaspaceSize
    
    
    # Metaspace 增长时的最大幅度。
    -XX:MaxMetaspaceExpansion
    
    # Metaspace 增长时的最小幅度。
    -XX:MinMetaspaceExpansion
    
    
    # 当进行过Metaspace GC之后, 会计算当前Metaspace的空闲空间比,如果空闲比大于这个参数,那么虚拟机会释放 Metaspace 的部分空间。在本机该参数的默认值为70,也就是70%。
    -XX:MaxMetaspaceFreeRatio
    
    # 当进行过Metaspace GC之后,会计算当前 Metaspace 的空闲空间比,如果空闲比小于这个参数,那么虚拟机将增长 Metaspace 的大小。在本机该参数的默认值为40,也就是40%。
    # 设置该参数可以控制 Metaspace 的增长的速度,太小的值会导致 Metaspace 增长的缓慢,Metaspace 的使用逐渐趋于饱和,可能会影响之后类的加载。而太大的值会导致 Metaspace 增长的过快,浪费内存。
    -XX:MinMetaspaceFreeRatio

    public static void main(String[] args) {
        ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean();
        // 借助 CGlib 来动态地生成大量的 Class
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(MetaSpaceOomError.class);
            enhancer.setCallbackTypes(new Class[]{Dispatcher.class, MethodInterceptor.class});
            enhancer.setCallbackFilter(new CallbackFilter() {
                @Override
                public int accept(Method method) {
                    return 1;
                }
    
                @Override
                public boolean equals(Object obj) {
                    return super.equals(obj);
                }
            });
            Class clazz = enhancer.createClass();
    
            System.out.println(clazz.getName() + "===================================");
            // 显示数量信息(共加载过的类型数目,当前还有效的类型数目,已经被卸载的类型数目)
            System.out.println("total:" + loadingBean.getTotalLoadedClassCount());
            System.out.println("active:" + loadingBean.getLoadedClassCount());
            System.out.println("unloaded:" + loadingBean.getUnloadedClassCount());
        }
    }

    五、DirectoryMemoryOomError(直接内存内存溢出)

    在使用 ByteBuffer 中的 allocateDirect() 的时候会出现,很多 Java NIO(如 netty)的框架中被封装为其他的方法,出现该问题时会抛出 java.lang.OutOfMemoryError: Direct buffer memory。

    如果你在直接或间接使用了 ByteBuffer 中的 allocateDirect 方法,而不做 clear 就会出现类似的问题。

    # 堆外内存最大值
    -XX:MaxDirectMemorySize

    private static int ONE_MB = 1024 * 1024;
    private static int index = 0;
    
    public static void main(String[] args) {
        try {
            System.out.println(VM.maxDirectMemory() / ONE_MB);
            ByteBuffer.allocateDirect(ONE_MB * 100);
    
            // 直接内存操作
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            Unsafe unsafe = (Unsafe) field.get(null);
            while (true) {
                index++;
                // 分配内存
                long l = unsafe.allocateMemory(ONE_MB);
                // 释放内存
                unsafe.freeMemory(l);
            }
        } catch (Exception | Error e) {
            System.out.println("index:" + index);
            e.printStackTrace();
        }
    }

    六、StackOomError(栈内存溢出)

    当一个线程执行一个Java方法时,JVM将创建一个新的栈帧并且把它push到栈顶。

    当一个方法递归调用自己时,每层调用都需要创建一个新的栈帧。当栈中越来越多的内存将随着递归调用而被消耗,最终造成 java.lang.StackOverflowError。

    # 每个线程的堆栈大小
    -Xss

    private static int num = 1;
    
    public void testStack() throws StackOverflowError {
        num++;
        this.testStack();
    }
    
    public static void main(String[] agrs) {
        try {
            StackOomError t = new StackOomError();
            t.testStack();
        } catch (StackOverflowError stackOverflowError) {
            System.out.println(num);
            stackOverflowError.printStackTrace();
        }
    }

    七、ArrayLimitOomError(数组超限内存溢出)

    JVM 对应用程序所能分配数组最大大小是有限制的,Java 数组的索引是 int 类型,不同的平台限制有所不同。

    在为数组分配内存之前,会执行特定平台的检查:分配的数据结构是否在此平台是可寻址的。

    若数组长度超出系统上限就会造成 java.lang.OutOfMemoryError: Requested array size exceeds VM limit。

    public static void main(String[] args) {
        try {
            int[] arr = new int[Integer.MAX_VALUE];
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }


    https://segmentfault.com/a/1190000017226359

    https://blog.csdn.net/bolg_hero/article/details/78189621

  • 相关阅读:
    嵌入式GUI FTK介绍(11)交叉编译
    3G手机 。Android 。Broncho
    PXA300/310的2D图形加速示例代码
    在终端下修改Android手机(Broncho A1)的系统设置
    FTK google group开通,欢迎加入交流。
    使用WebDeployment Project改善VS2005发布网站问题
    IIS 伪静态设置
    使用jQuery简化Ajax开发——Ajax开发入门[令狐葱翻译版part1]
    web.config文件中的特殊字符处理
    网上找的asp.net伪静态教程,大晚上补补课
  • 原文地址:https://www.cnblogs.com/jhxxb/p/11100480.html
Copyright © 2011-2022 走看看