JVM学习之内存溢出

查看JVM参数的网站地址: https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

Java堆内存溢出异常测试

package jvm;

import java.util.ArrayList;
import java.util.List;

/**
 * @author: guanglai.zhou
 * @date: 2021/6/17 13:27
 * @description: VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 * @version: 1.0
 */
public class HeapOOM {

    static class OOMObject {

    }

    public static void main(String[] args) {

        List<OOMObject> list = new ArrayList<>();

        while (true) {
            list.add(new OOMObject());
        }

    }

}

设置JVM参数 -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
在这里插入图片描述
执行结果堆内存溢出,并且生成dump文件
在这里插入图片描述
控制台信息如下

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid3184.hprof ...
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3210)
	at java.util.Arrays.copyOf(Arrays.java:3181)
	at java.util.ArrayList.grow(ArrayList.java:265)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
	at java.util.ArrayList.add(ArrayList.java:462)
	at jvm.HeapOOM.main(HeapOOM.java:23)
Heap dump file created [28453527 bytes in 0.185 secs]

通过工具分析dump文件,在jdk的工具中打开jvisualvm.exe,通过文件->装入加载堆dump文件

在这里插入图片描述

基本信息如下所示

    生成的日期: Thu Jun 17 13:30:48 CST 2021
    文件: E:\spring\docker-demo\java_pid3184.hprof
    文件大小: 27.1 MB

    字节总数: 20,361,853
    类总数: 606
    实例总数: 819,846
    类加载器: 2
    垃圾回收根节点: 593
    等待结束的暂挂对象数: 0

    在出现 OutOfMemoryError 异常错误时进行了堆转储
    导致 OutOfMemoryError 异常错误的线程: main

还可以看到系统属性

    awt.toolkit=sun.awt.windows.WToolkit
    file.encoding=UTF-8
    file.encoding.pkg=sun.io
    file.separator=\
    java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment
    java.awt.printerjob=sun.awt.windows.WPrinterJob
    java.class.path=C:\Program Files\Java\jdk1.8.0_202\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\rt.jar;E:\spring\docker-demo\target\classes;D:\maven\repo\org\springframework\boot\spring-boot-starter-web\2.4.4\spring-boot-starter-web-2.4.4.jar;D:\maven\repo\org\springframework\boot\spring-boot-starter\2.4.4\spring-boot-starter-2.4.4.jar;D:\maven\repo\org\springframework\boot\spring-boot\2.4.4\spring-boot-2.4.4.jar;D:\maven\repo\org\springframework\boot\spring-boot-autoconfigure\2.4.4\spring-boot-autoconfigure-2.4.4.jar;D:\maven\repo\org\springframework\boot\spring-boot-starter-logging\2.4.4\spring-boot-starter-logging-2.4.4.jar;D:\maven\repo\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\maven\repo\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\maven\repo\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;D:\maven\repo\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;D:\maven\repo\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\maven\repo\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\maven\repo\org\yaml\snakeyaml\1.27\snakeyaml-1.27.jar;D:\maven\repo\org\springframework\boot\spring-boot-starter-json\2.4.4\spring-boot-starter-json-2.4.4.jar;D:\maven\repo\com\fasterxml\jackson\core\jackson-databind\2.11.4\jackson-databind-2.11.4.jar;D:\maven\repo\com\fasterxml\jackson\core\jackson-annotations\2.11.4\jackson-annotations-2.11.4.jar;D:\maven\repo\com\fasterxml\jackson\core\jackson-core\2.11.4\jackson-core-2.11.4.jar;D:\maven\repo\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.11.4\jackson-datatype-jdk8-2.11.4.jar;D:\maven\repo\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.11.4\jackson-datatype-jsr310-2.11.4.jar;D:\maven\repo\com\fasterxml\jackson\module\jackson-module-parameter-names\2.11.4\jackson-module-parameter-names-2.11.4.jar;D:\maven\repo\org\springframework\boot\spring-boot-starter-tomcat\2.4.4\spring-boot-starter-tomcat-2.4.4.jar;D:\maven\repo\org\apache\tomcat\embed\tomcat-embed-core\9.0.44\tomcat-embed-core-9.0.44.jar;D:\maven\repo\org\glassfish\jakarta.el\3.0.3\jakarta.el-3.0.3.jar;D:\maven\repo\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.44\tomcat-embed-websocket-9.0.44.jar;D:\maven\repo\org\springframework\spring-web\5.3.5\spring-web-5.3.5.jar;D:\maven\repo\org\springframework\spring-beans\5.3.5\spring-beans-5.3.5.jar;D:\maven\repo\org\springframework\spring-webmvc\5.3.5\spring-webmvc-5.3.5.jar;D:\maven\repo\org\springframework\spring-aop\5.3.5\spring-aop-5.3.5.jar;D:\maven\repo\org\springframework\spring-context\5.3.5\spring-context-5.3.5.jar;D:\maven\repo\org\springframework\spring-expression\5.3.5\spring-expression-5.3.5.jar;D:\maven\repo\commons-io\commons-io\2.6\commons-io-2.6.jar;D:\maven\repo\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\maven\repo\org\springframework\spring-core\5.3.5\spring-core-5.3.5.jar;D:\maven\repo\org\springframework\spring-jcl\5.3.5\spring-jcl-5.3.5.jar;E:\Program Files\JetBrains\IntelliJ IDEA 2019.3.1\lib\idea_rt.jar
    java.class.version=52.0
    java.endorsed.dirs=C:\Program Files\Java\jdk1.8.0_202\jre\lib\endorsed
    java.ext.dirs=C:\Program Files\Java\jdk1.8.0_202\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
    java.home=C:\Program Files\Java\jdk1.8.0_202\jre
    java.io.tmpdir=C:\Users\GUANGL~1.ZHO\AppData\Local\Temp\
    java.library.path=C:\Program Files\Java\jdk1.8.0_202\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Program Files\Java\jdk1.8.0_202\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Lenovo\Fingerprint Manager Pro\;D:\Program Files\apache-maven-3.6.3\bin;C:\Program Files\TortoiseSVN\bin;E:\spring\spring-boot-cli-2.2.0.RELEASE-bin\spring-2.2.0.RELEASE\bin;D:\Program Files\Git\cmd;D:\Program Files\gradle-7.0\bin;.
    java.runtime.name=Java(TM) SE Runtime Environment
    java.runtime.version=1.8.0_202-b08
    java.specification.name=Java Platform API Specification
    java.specification.vendor=Oracle Corporation
    java.specification.version=1.8
    java.vendor=Oracle Corporation
    java.vendor.url=http://java.oracle.com/
    java.vendor.url.bug=http://bugreport.sun.com/bugreport/
    java.version=1.8.0_202
    java.vm.info=mixed mode
    java.vm.name=Java HotSpot(TM) 64-Bit Server VM
    java.vm.specification.name=Java Virtual Machine Specification
    java.vm.specification.vendor=Oracle Corporation
    java.vm.specification.version=1.8
    java.vm.vendor=Oracle Corporation
    java.vm.version=25.202-b08
    line.separator=\r\n
    os.arch=amd64
    os.name=Windows 7
    os.version=6.1
    path.separator=;
    sun.arch.data.model=64
    sun.boot.class.path=C:\Program Files\Java\jdk1.8.0_202\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\rt.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\sunrsasign.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_202\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_202\jre\classes
    sun.boot.library.path=C:\Program Files\Java\jdk1.8.0_202\jre\bin
    sun.cpu.endian=little
    sun.cpu.isalist=amd64
    sun.desktop=windows
    sun.io.unicode.encoding=UnicodeLittle
    sun.java.command=jvm.HeapOOM
    sun.java.launcher=SUN_STANDARD
    sun.jnu.encoding=GBK
    sun.management.compiler=HotSpot 64-Bit Tiered Compilers
    sun.os.patch.level=Service Pack 1
    user.country=CN
    user.dir=E:\spring\docker-demo
    user.home=C:\Users\guanglai.zhou
    user.language=zh
    user.name=guanglai.zhou
    user.script=
    user.timezone=
    user.variant=

在类选项中可以看到98.8的实例为OOMObject类型
在这里插入图片描述

运行时常量池导致的内存溢出异常

package jvm;

import java.util.HashSet;
import java.util.Set;

/**
 * @author: guanglai.zhou
 * @date: 2021/6/17 13:45
 * @description: VM args: -XX:PermSize=6M -XX:MaxPermSize=6M
 * 在JDK7以上 PermSize已经无效了
 * 需要设置堆的大小 -Xmx6m
 * @version: 1.0
 */
public class RuntimeConstantPoolOOM {

    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        short i = 0;
        while (true){
            set.add(String.valueOf(i++).intern());
        }
    }

}

在这里插入图片描述

运行结果如下

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
	at java.lang.Integer.toString(Integer.java:401)
	at java.lang.String.valueOf(String.java:3099)
	at jvm.RuntimeConstantPoolOOM.main(RuntimeConstantPoolOOM.java:20)

以上结果是在JDK8中的测试结果(单纯设置JVM参数-XX:PermSize=6M -XX:MaxPermSize=6M是没有作用,程序会一直跑下去),因为在JDK7之后字符串常量是存放在堆当中的,所以设置永久代大小已经没有任何作用了,只能通过限制堆的大小测试出异常。

方法区内存溢出异常

在JDK1.8当中,不存在永久代,方法区其实是在元空间中的,因为通过指定元空间的大小来测试方法区内存溢出异常

设置元空间最大值

-XX:MaxMetaspaceSize=size
Sets the maximum amount of native memory that can be allocated for class metadata. By default, the size is not limited. The amount of metadata for an application depends on the application itself, other running applications, and the amount of memory available on the system.

The following example shows how to set the maximum class metadata size to 256 MB:

-XX:MaxMetaspaceSize=256m

设置元空间开始大小

-XX:MetaspaceSize=size
Sets the size of the allocated class metadata space that will trigger a garbage collection the first time it is exceeded. This threshold for a garbage collection is increased or decreased depending on the amount of metadata used. The default size depends on the platform.

package jvm;

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

import java.lang.reflect.Method;

/**
 * @author: guanglai.zhou
 * @date: 2021/6/17 13:59
 * @description: VM args: -XX:PermSize=6M -XX:MaxPermSize=6M
 * 在JDK1.8当中 设置永久代没有意义了 方法区放在了元空间 通过以下命令设置元空间大小
 * -XX:MaxMetaspaceSize=64m -XX:MetaspaceSize=64m
 * @version: 1.0
 */
public class JavaMethodAreaOOM {

    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMObject.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, args);
                }
            });
            enhancer.create();
        }
    }

    static class OOMObject {

    }
}

在这里插入图片描述
运行结果如下

Exception in thread "main" org.springframework.cglib.core.CodeGenerationException: java.lang.OutOfMemoryError-->Metaspace
	at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:557)
	at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:363)
	at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:585)
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:131)
	at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319)
	at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:572)
	at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:387)
	at jvm.JavaMethodAreaOOM.main(JavaMethodAreaOOM.java:30)
Caused by: java.lang.OutOfMemoryError: Metaspace
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
	at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:554)
	... 7 more

Process finished with exit code 1

直接内存溢出异常

package jvm;

import sun.misc.Unsafe;

import java.lang.reflect.Field;

/**
 * @author: guanglai.zhou
 * @date: 2021/6/17 14:36
 * @description:  -Xmx20m -XX:MaxDirectMemorySize=10M
 * @version: 1.0
 */
public class DirectMemoryOOM {

    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) throws IllegalAccessException {
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while (true) {
            unsafe.allocateMemory(_1MB);
        }
    }

}

设置直接内存大小

-XX:MaxDirectMemorySize=size
Sets the maximum total size (in bytes) of the New I/O (the java.nio package) direct-buffer allocations. Append the letter k or K to indicate kilobytes, m or M to indicate megabytes, g or G to indicate gigabytes. By default, the size is set to 0, meaning that the JVM chooses the size for NIO direct-buffer allocations automatically.

The following examples illustrate how to set the NIO size to 1024 KB in different units:

-XX:MaxDirectMemorySize=1m
-XX:MaxDirectMemorySize=1024k
-XX:MaxDirectMemorySize=1048576

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lang20150928

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值