首页 > 作文

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

更新时间:2023-04-04 05:55:54 阅读: 评论:0

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

jvm(java virtual machine),简而言之就是java程序的运行环境(java二进制字节码的运行环境)。以下表格比较了jvm、jre和jdk之间的关系:

jvmjava virtual machinejrejvm+基础类库jdkjvm+基础类库+编译工具开发java程序jdk+ide工具开发javaee程序jdk+ide工具+应用服务器

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

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

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

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

当方法结束调用后,对应的栈帧就会被移除出栈。

我们以debug方式运行代码:

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

所以可以知道,垃圾回收不涉及栈内存,因为方法调用完被移除之后,内存就会被释放掉。我们可以通过-xss设定栈内存的大小,但是请注意,因为海参小米粥我们的物理内存是固定的,所以栈内存并不是越大越好,栈内存设置的越大,我们的线程数量反而越少。

既然可以分配栈的大小,那么什么情况下会出现栈内存溢出呢?第一种是栈帧过多导致栈内存溢出,第二种就是栈帧过大导致栈内存溢出。请看如下代码:

public class demo1_3 {    public static void main(string args[]) {        try {            m1();        }catch (exception e) {            e.printstacktrace();        }    }    private static void m1() {        m1();    }}

由于对m1进行了递归调用,且没有设置退出条件,所以运行后会抛出栈内存溢出错误:

exception in thread "main" java.lang.stackoverflowerror

这里还有一个问题,如果多个线程执行m1方法,内部的变量x是线程安全的吗?答案是肯定的,因为每个线程都有自己的栈,栈内的栈帧都会存在自己的变量x,所以方法内的局部变量是线程安全的。

publforever aloneic class demo1_2 {    static void m1() {        int x = 0;        for (int i=0; i<5000; i++) {            x ++;        }        system.out.println(x);    }}

但是如果变量x是每个方法公有的,那就需要考虑线程安全的问题了,比如用static修饰:

static int x = 0;

3、本地方法栈,就是给本地方法的运行提供运行空间。本地方法,指那些不是由java代码编写的方法,可以通过本地方法去调用解释器、即时编译器或者垃圾回收器。比如object类中的clone()方法,真正实现的是c和c++:

protected native object clone() throws clonenotsupportedexception;

4、堆。通过new创建的对象都会使用堆内存,可以通过-xmx设定堆空间大小。堆有两大特点,一是线程共享,堆中的对象都需要考虑线程安全的问题,二是它有垃圾回收机制。

我们首先看一下堆内存溢出的问题,请看如下代码:

public class demo衡山旅游1_4{    public static void main(string args[]) {        try {            list<string> list = new arraylist<>();            string a = "hello";            while(true) {                list.add(a);                a = a + a;            }        }catch (exception e) {            e.printstacktrace();        }    }}

运行后抛出堆内存溢出错误:

exception in thread "main" java.lang.outofmemoryerror: java heap space韩服dnf二次觉醒

5、方法区,是所有jvm共享的区域,存储了跟类的结构相关的信息:运行时常量池,类的成员变量,方法数据,以及成员方法和构造器方法的代码等。方法区是在jvm启动时被创建的,可以通过-xx:maxmetaspacesize=10m设置方法区的大小。下图就是jdk1.8中的内存结构:

可以看到,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(opco300字作文大全des.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.

本文发布于:2023-04-04 05:55:53,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/1f9fa2324f0cc20fa271bd79be7eff42.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:java heap space解决方法(jvm设置堆内存参数).doc

本文 PDF 下载地址:java heap space解决方法(jvm设置堆内存参数).pdf

标签:方法   内存   线程   程序
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图