您的位置:首页 > 运维架构 > Tomcat

JVM内存设置,各个参数含义和设置后不起作用问题

2018-01-11 16:00 351 查看
这两天才来公司,遇到很棘手的问题,把公司项目下载下来后无法运行,报错内存溢出问题,然后网上一大堆问题的答案,按照网上的答案解决了tomcat:java.lang.OutOfMemoryError: PermGen space问题,但是后面还有tomcat:java.lang.OutOfMemoryError: Java heap space问题。按照网上的说法设置并没有解决我的问题,于是开始太多JVM内存机制。在这里终结一下怎样解决的问题,希望能帮助自己和他人。如有错误,请大佬指出。
首先来看一下JVM内存有哪些区域,主要的作用是什么?(摘自http://blog.csdn.net/zhoudaxia/article/details/26454421/)


运行时数据区(Runtime Data Areas)



图 4: 运行时数据区

  运行时数据区是在JVM运行的时候操作系统所分配的内存区。运行时内存区可以划分为6个区域。在这6个区域中,一个PC Register,JVM stack 以及Native Method Statck都是按照线程创建的,Heap,Method Area以及Runtime Constant Pool都是被所有线程公用的。
 PC寄存器(PC register):每个线程启动的时候,都会创建一个PC(Program Counter,程序计数器)寄存器。PC寄存器里保存有当前正在执行的JVM指令的地址。
JVM 堆栈(JVM stack):每个线程启动的时候,都会创建一个JVM堆栈。它是用来保存栈帧的。JVM只会在JVM堆栈上对栈帧进行push和pop的操作。如果出现了异常,堆栈跟踪信息的每一行都代表一个栈帧立的信息,这些信息是通过类似于printStackTrace()这样的方法来展示的。



图 5: JVM堆栈

  --- 栈帧(stack frame):每当一个方法在JVM上执行的时候,都会创建一个栈帧,并且会添加到当前线程的JVM堆栈上。当这个方法执行结束的时候,这个栈帧就会被移除。每个栈帧里都包含有当前正在执行的方法所属类的本地变量数组,操作数栈,以及运行时常量池的引用。本地变量数组的和操作数栈的大小都是在编译时确定的。因此,一个方法的栈帧的大小也是固定不变的。

  --- 局部变量数组(Local variable array):这个数组的索引从0开始。索引为0的变量表示这个方法所属的类的实例。从1开始,首先存放的是传给该方法的参数,在参数后面保存的是方法的局部变量。

  --- 操作数栈(Operand stack):方法实际运行的工作空间。每个方法都在操作数栈和局部变量数组之间交换数据,并且压入或者弹出其他方法返回的结果。操作数栈所需的最大空间是在编译期确定的。因此,操作数栈的大小也可以在编译期间确定。
 本地方法栈(Native method stack):供用非Java语言实现的本地方法的堆栈。换句话说,它是用来调用通过JNI(Java Native Interface Java本地接口)调用的C/C++代码。根据具体的语言,一个C堆栈或者C++堆栈会被创建。
 方法区(Method area):方法区是所有线程共享的,它是在JVM启动的时候创建的。它保存所有被JVM加载的类和接口的运行时常量池,成员变量以及方法的信息,静态变量以及方法的字节码。JVM的提供者可以通过不同的方式来实现方法区。在Oracle 的HotSpot JVM里,方法区被称为永久区或者永久代(PermGen)。是否对方法区进行垃圾回收对JVM的实现是可选的。
  运行时常量池(Runtime constant pool):这个区域和class文件里的constant_pool是相对应的。这个区域是包含在方法区里的,不过,对于JVM的操作而言,它是一个核心的角色。因此在JVM规范里特别提到了它的重要性。除了包含每个类和接口的常量,它也包含了所有方法和变量的引用。简而言之,当一个方法或者变量被引用时,JVM通过运行时常量区来查找方法或者变量在内存里的实际地址。
堆(Heap):用来保存实例或者对象的空间,而且它是垃圾回收的主要目标。当讨论类似于JVM性能之类的问题时,它经常会被提及。JVM提供者可以决定怎么来配置堆空间,以及不对它进行垃圾回收。

我这里的异常tomcat:java.lang.OutOfMemoryError: Java heap space是堆空间不足,接着来看设置JVM的参数和各个参数的含义。(摘自:http://blog.csdn.net/shenhonglei1234/article/details/54950663)





上图中,刻画了Java程序运行时的堆空间,可以简述成如下2条

1.JVM中堆空间可以分成三个大区,新生代、老年代、永久代

2.新生代可以划分为三个区,Eden区,两个幸存区

在JVM运行时,可以通过配置以下参数改变整个JVM堆的配置比例
1.JVM运行时堆的大小

  -Xms堆的最小值

  -Xmx堆空间的最大值

2.新生代堆空间大小调整

  -XX:NewSize新生代的最小值

  -XX:MaxNewSize新生代的最大值

  -XX:NewRatio设置新生代与老年代在堆空间的大小

  -XX:SurvivorRatio新生代中Eden所占区域的大小

3.永久代大小调整

  -XX:MaxPermSize

4.其他

   -XX:MaxTenuringThreshold,设置将新生代对象转到老年代时需要经过多少次垃圾回收,但是仍然没有被回收

接着我在myeclipse.ini配置文件中配置参数(公司老员工给我的配置参数)
-Xms1024m
-Xmx2048m
-XX:MaxPermSize=512m
-XX:ReservedCodeCacheSize=64m
重启项目,然而还是tomcat:java.lang.OutOfMemoryError: Java heap space问题,很郁闷,应该是对的啊。最终我使用jdk里面的工具(jdk安装目录下bin中的)jvisualvm工具(直接双击,前提是tomcat运行状态,才能选择连接到tomcat),连接tomcat后查看内存参数,发现我的虚拟机只有256M的内存(下图是改了过后,有1581252608b)。不应该啊,我明明配置了的啊!!



然后我把-Xmx2048m改成了-Xmx1024m,自从运行就好了,他就好了,很少惊讶,不知道为什么,但是最后发现只要我的-Xms和-Xmx参数设置为一样大小就会起作用,具体原因不详
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息