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


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

文章插图
我们首先了解下什么是JVM 。
JVM(Java Virtual Machine),简而言之就是java程序的运行环境(java二进制字节码的运行环境) 。以下表格比较了JVM、JRE和JDK之间的关系:
JVMJava Virtual MachineJREJVM+基础类库JDKJVM+基础类库+编译工具开发javase程序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,所以方法内的局部变量是线程安全的 。
public 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 Demo1_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();}}}运行后抛出堆内存溢出错误:


以上关于本文的内容,仅作参考!温馨提示:如遇健康、疾病相关的问题,请您及时就医或请专业人士给予相关指导!

「四川龙网」www.sichuanlong.com小编还为您精选了以下内容,希望对您有所帮助: