java heap space解决方法(jvm设置堆内存参数)

我们首先了解下什么是JVM。

JVM(Java Virtual Machine),简而言之就是java程序的运行环境(java二进制字节码的运行环境)。以下表格比较了JVM、JRE和JDK之间的关系:

JVM Java Virtual Machine JRE JVM+基础类库 JDK JVM+基础类库+编译工具 开发javase程序 JDK+IDE工具 开发javaee程序 JDK+IDE工具+应用服务器

JVM的内存可以分为5大块:程序计数器、虚拟机栈、本地方法栈、堆以及方法区

1、程序计数器,也称为寄存器。我们知道,java程序的执行顺序是jvm指令->解释器->机器码->CPU,那么程序计数器的作用就是在程序执行的过程中,记住下一条JVM指令的执行地址。当执行完当前JVM指令之后,会在程序计数器中获取到下一条JVM指令的地址,以此去寻找下一条指令。

要记住,程序计数器是每条线程私有的。当线程因为某种原因暂停执行后,该条线程的程序计数器会记录下条指令的地址,等结束暂停后,线程可以从停止的地方继续执行。而且,程序计数器不会存在内存溢出。

2、虚拟机栈,就是每个线程运行需要的内存空间。一个栈由多个栈帧组成,栈帧对应着每个方法运行时需要的内存(参数,局部变量,返回地址等),每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法。

java heap space解决方法(jvm设置堆内存参数)

查看debug界面可以发现,main、method1和method2方法都以上文的方式被压入栈中:

java heap space解决方法(jvm设置堆内存参数)

可以看到,Metaspace作为方法区的实现,包含了Class、ClassLoader和常量池。方法区也会有内存溢出,即元空间的内存溢出:

public class Demo1_5 extends ClassLoader{    public static void main(String args[]) {        try {            Demo1_5 test = new Demo1_5();            //加载10000个新的类            for (int i=0; i<10000; i++) {                //生成类的二进制字节码                ClassWriter cw = new ClassWriter(0);                //参数含义:版本号,public,类名,包名,父类,接口                cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "Class"+i, null, "java/lang/object", null);                //返回类的byte数组                byte[] code = cw.toByteArray();                //执行类的加载                test.defineClass("Class"+i, code, 0, code.length);            }        }catch (Exception e) {            e.printStackTrace();        }    }}

上述案例演示了加载的类数量过多导致元空间内存溢出,以下是运行后结果:

Error occurred during initialization of VMMaxMetaspaceSize is too small.
(0)
小多多的头像小多多创始人

相关推荐

发表回复

登录后才能评论