之前一篇文章讲解了关于tomcat的相关知识https://blog.csdn.net/bebmwnz/article/details/89968824,今天再来说说jvm内存及其优化的东西。本篇文章也是几百家所长结合自己的了解总结出来的,希望对大家有所帮助。在讲之前先来贴张图(丑是丑了点,但是包含了你想要的东西,勿喷)。
jvm内存包括堆(heap)、栈(stack)、方法区(method)、本地方法栈和程序计数器组成(本地方法栈和程序计数器组成在文中不做过多解释)。
Heap Space(堆):Java堆是JVM所管理的最大一块内存,所有线程共享这块内存区域,几乎所有的对象实例都在这里分配内存,因此,它也是垃圾收集器管理的主要区域。从内存回收的角度来看,由于现在的收集器基本都采用分代收集算法,所以通常把堆分为新生代(Young Generation)和老年代(Old Generation),而新生代又可以分为伊甸区(Eden)、幸存区0(From Survivor0)和幸存区1(To Surivivor 1)三部分。有一点需要注意:Java堆空间只是在逻辑上是连续的,在物理上并不一定是连续的内存空间。
堆内存=新生代+老年代,不包含永久代!!堆内存=新生代+老年代,不包含永久代!!堆内存=新生代+老年代,不包含永久代!!
VM Stack(堆):线程私有,生命周期和线程一致,随着线程的结束而消亡。虚拟机栈用于描述Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息。
Method Area (方法区):所有线程共享的内存区域。它用于存储已被虚拟机加载的类信息、常量、静态变量、JIT编译后的代码等数据。在Java虚拟机规范中,方法区属于堆的一个逻辑部分,但很多情况下,都把方法区与堆区分开来说。大家平时开发中通过反射获取到的类名、方法名、字段名称、访问修饰符等信息都是从这块区域获取的。
对于HotSpot虚拟机,方法区对应为永久代(Permanent Generation),但本质上,两者并不等价,仅仅是因为HotSpot虚拟机的设计团队是用永久代来实现方法区而已,对于其他的虚拟机(JRockit、J9)来说,是不存在永久代这一概念的。
到JDK1.8时,永久代已经被“元空间”Metaspace取代。在JDK1.8中,JVM参数-XX:PermSize
和-XX:MaxPermSize
已经失效,取而代之的是-XX:MetaspaceSize
和-XX:MaxMetaspaceSize
。注意:Metaspace已经不再使用堆空间,转而使用Native Memory
内存参数及其含义:
-Xms:初始堆大小
-Xmx:最大堆大小(一般为了防止由于初始值较小而不停的申请内存带来的开销,会将Xms和Xmx设置为相同的数值)
-XX:NewSize=n:设置年轻代大小
-XX:NewRatio=n:设置年轻代(包括Eden和两个Survivor区)和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个堆内存的1/4。Sun官方建议年轻代的大小为整个堆的3/8左右,可以简单的设置为整个堆内存的1/3
-Xss:设置每个线程的堆栈大小
-XX:PermSize (或Xmn)永久代初始大小(JDK8以前) -XX:MetaspaceSize(JDK8及以后)
-XX:MxPermSize (或Xmn)永久代最大值(JDK8以前) -XX:MaxMetaspaceSize(JDK8及以后)
内存大小设置:
Java整个堆大小设置,Xmx 和 Xms设置为老年代存活对象(不是老年代)的3-4倍,即FullGC之后的老年代内存占用的3-4倍
永久代 PermSize和MaxPermSize设置为老年代存活对象(不是老年代)的1.2-1.5倍。
年轻代Xmn的设置为老年代存活对象(不是老年代)的1-1.5倍。
老年代的内存大小设置为老年代存活对象(不是老年代)的2-3倍。