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

原文地址:https://www.cnblogs.com/jhxxb/p/11100480.html

时间: 2024-10-20 20:33:48

Java-JVM OutOfMemory 情况(JDK8)的相关文章

Java JVM虚拟机选项Xms/Xmx/PermSize/MaxPermSize(转)

通过JVM的这些选项:Xms/Xmx/PermSize/MaxPermSize可以牵扯出很多问题,比如性能调优等. 说明:以下转载没经过实践. 经验实例(参考): 设置每个线程的堆栈大小.JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右. 参数的含义: -vmargs -Xms128M -Xmx512M

java JVM垃圾回收机制

Java语言出来之前,大家都在拼命的写C或者C++的程序,而此时存在一个很大的矛盾,C++等语言创建对象要不断的去开辟空间,不用的时候有需要不断的去释放控件,既要写构造函数,又要写析构函数,很多时候都在重复的allocated,然后不停的~析构.于是,有人就提出,能不能写一段程序在实现这块功能,每次创建,释放控件的时候复用这段代码,而无需重复的书写呢? 1960年 基于MIT的Lisp首先提出了垃圾回收的概念,用于处理C语言等不停的析构操作,而这时Java还没有出世呢!所以实际上GC并不是Jav

Java多线程学习笔记——从Java JVM对多线程数据同步的一些理解

   我们知道在多线程编程中,我们很大的一部分内容是为了解决线程间的资源同步问题和线程间共同协作解决问题.线程间的同步,通俗我们理解为僧多粥少,在粥有限情况下,我们怎么去防止大家有秩序的喝到粥,不至于哄抢都没得喝.线程讲协作,我们可以理解为我们在医院看病的时候,我们要先挂号,才能看病.现在医院有很多病人排队,怎么协调病人都有秩序的先挂号,后看病.本篇文章的重点不在此,也不是在此一下子能分析完,我们先从Java JVM的角度来理解多线程的一些方面. 我们知道多线程间的数据同步,我们是通过加锁的操作

Powershell远程在Azure A7虚拟机执行Java JVM失败

近期.使用Powershell脚本在A7 (8核,56G内存)配置的 Azure VM(Virtual Machine.虚拟机)上远程运行Java JVM时 (java.exe -version).总是失败并返回例如以下的错误信息. 相同的Powershell脚本.在其他低于A7配置的VM上远程运行一切正常:此外,假设使用远程桌面登录到VM上,再进行相同的操作,一切运行正常. Error occurred during initialization of VM Unable to allocat

认识 java JVM虚拟机选项 Xms Xmx PermSize MaxPermSize 区别

点击window---->preferences---->配置的tomcat---->JDK,在Optional Java VM arguments:中输入 -Xmx512M -Xms256M -XX:MaxPermSize=256m, 如下图所示: Eclipse崩溃,错误提示: MyEclipse has detected that less than 5% of the 64MB of Perm Gen (Non-heap memory) space remains. It is

java JVM常见的四大异常及处理方案

区域 作用 异常 控制参数 解决思路 java堆 存放对象的实例. java.lang.OutOfMemory Error:Java heap space -Xms(初始化堆), -Xmx(最大堆), -Xmn(新生代) 1.先查看是不是内存泄漏(内存中的对象是不是必须的),如果是泄漏,则找到与GC root 的路径解决泄漏. 2.看物理内存是否允许加大-Xms,-Xmx. 3.检查堆中是不是有对象实例一直在内存中没有释放. 4.技巧让-Xms = -Xmx,减少内存扩展的开销. 虚拟机栈和本地

Java JVM、JNI、Native Function Interface、Create New Process Native Function API Analysis

目录 1. JAVA JVM 2. Java JNI: Java Native Interface 3. Java Create New Process Native Function API Analysis In Linux 4. Java Create New Process Native Function API Analysis In Windows 1. JAVA JVM 0x1: JVM架构简介 JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种

Java JVM使用哪种编码格式

Java JVM使用哪种编码格式 A ASCII characters  B Unicode characters C Cp1252 D UTF-8 E GBK F GBK2312 答案:B   在JVM内部,统一使用Unicode Java JVM使用哪种编码格式

java JVM

1.ClassLoader(类加载器) 1.加载:查找并加载类的二进制数据 2.连接 —验证:确保被加载的类的正确性(防止不是通过java命令生成的class文件被加载) —准备:为类的静态变量分配内存,并将其初始化为默认值(如int默认值为0) —解析:把类中的符号引用转换为直接引用 3.初始化:为类的静态变量赋予正确的初始值(即代码中指定的值 例:public static int a = 2) JAVA程序对类的使用方式可以分为两种 —主动使用(六种) —被动使用(除了主动使用的六种方法,

java jvm概述

java jvm 有分层的思想. java类..java文件,源文件,源代码,源程序 编译器不能把源代码直接编译成0101,除非是java语言写的操作系统. windows认识的可执行文件是.exe文件,windows操作系统可以把.exe文件翻译成0101.