jvm内存模型---方法区,虚拟机栈,本地方法栈,堆,程序计数器
方法区:又称永久代,非堆,用于存储虚拟机加载的类信息,常量,静态变量,是各个线程共享的内存区域,
-XX:PermSize 设置方法区大小 (在jdk1.7之前叫PermSize 在jdk1.7之后叫metaspace)
-XX:MaxPermSize 设置方法区最大限制
虚拟机栈;
描述的是Java方法执行的内存模型,每个方法在执行的时候,都会创建一个“栈帧”,用于存储局部变量表,操作栈,方法出口等信息,每个方法被调用执行完的过程就代表着一个“栈帧”在虚拟机栈中从入栈到出栈的过程
-Xss2m 这样设置成2M
异常:Fatal:Stack size too small
异常的引起一般是线程数目太多
本地方法栈:
为一些native方法分配的stack
堆:
也叫做java堆或者GC堆,是java虚拟机所管理的内存中最大的一块内存区域,也是被各个线程共享的内存区域,在jvm创建时刻创建,该内存存放了对象实例。
jvm调优的重点区域:堆
Young(年轻代)
新生代进一步划分为3个区域:一个相对大点的区域,称为”伊甸园区(Eden)”;两个相对小点的区域称为”From 幸存区(survivor)”和”To 幸存区(survivor)”。按照规定,新对象会首先分配在 Eden 中(如果新对象过大,会直接分配在老年代中)。在GC中,Eden 中的对象会被移动到survivor中,直至对象满足一定的年纪(定义为熬过GC的次数),会被移动到老年代。
对象一般出生在Eden区,年轻代GC过程中,对象在2个幸存区之间移动,如果对象存活到适当的年龄,会被移动到老年代。当对象在老年代死亡时,就需要更高级别的GC,更重量级的GC算法(复制算法不适用于老年代,因为没有多余的空间用于复制)
现在应该能理解为什么新生代大小非常重要了(译者,有另外一种说法:新生代大小并不重要,影响GC的因素主要是幸存对象的数量),如果新生代过小,会导致新生对象很快就晋升到老年代中,在老年代中对象很难被回收。如果新生代过大,会发生过多的复制过程。我们需要找到一个合适大小,不幸的是,要想获得一个合适的大小,只能通过不断的测试调优。这就需要JVM参数了
-XX:NewSize and -XX:MaxNewSize
就像可以通过参数(-Xmsand -Xmx) 指定堆大小一样,可以通过参数指定新生代大小。设置XX:MaxNewSize 参数时,应该考虑到新生代只是整个堆的一部分,新生代设置的越大,老年代区域就会减少。一般不允许新生代比老年代还大,因为要考虑GC时最坏情况,所有对象都晋升到老年代。(译者:会发生OOM错误)-XX:MaxNewSize 最大可以设置为-Xmx/2.
考虑性能,一般会通过参数-XX:NewSize 设置新生代初始大小。如果知道新生代初始分配的对象大小(经过监控) ,这样设置会有帮助,可以节省新生代自动扩展的消耗。
-XX:NewRatio
可以设置新生代和老年代的相对大小。这种方式的优点是新生代大小会随着整个堆大小动态扩展。参数-XX:NewRatio 设置老年代与新生代的比例。例如-XX:NewRatio=3 指定老年代/新生代为3/1. 老年代占堆大小的3/4 ,新生代占1/4 .
Tenured(年老代)
年老代存放从年轻代存活的对象。一般来说年老代存放的都是生命期较长的对象。
Perm(持久代)----同时也叫方法区
用 于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate等, 在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=进行设置。
持久代一般固定大小为64m