最近学习了钟洪发老师的JVM课程后,总结得出以下经验,做个记录
一:JVM的内部结构
1、虚拟机栈
一个线程会创建一个栈
调用一个方法就会创建一个栈帧(简称入栈),直到方法返回一个结果(简称出栈)
虚拟机栈是一个后入先出的数据结构,例如(调用方A,A方法调用B方法,B方法又调用C方法,那么出栈时,肯定是C方法先执行完出栈,再到B,再到A)
栈里存放的是在调用方法时,产生的局部变量以及变量存储的数据
2、方法区
存储(类结构信息、常量池(基本类型的值),静态变量,构造函数),在类加载时,使用类加载器(Class Loader)中载入时,初始化的。
方法区会回收没有被使用过的变量
方法区里的数据是线程共享的
3、堆
存放对象的地方。所有用new关键字实例出来的对象都存放在堆。这个区会被垃圾回收频繁回收
写个例子:
static Integer i1 = new Integer(1);
static Integer i2 = new Integer(1);
static Integer a = 1;
static Integer a = 2;
public static void main(String[] args){
System.out.println(i1 == i2);//返回false new出来的对象内存地址指向堆
System.out.println(a == b);//返回true int类型的值1 是存放在方法区的,a,b都指向方法区常量池的内存地址,是同一个
}
二、堆的内部结构
1、堆分为新生代,老年代
新生代又分为:Eden(伊甸园)、Survivor(幸存者):分为大小对称的两个区域 S0 S1
2、新new出来的对象会进入到新生代的Eden中,当Eden内存被放满之后,会执行普通的垃圾回收minor gc
minor gc执行之后,幸存下来的对象,会被放入到s0或s1当中,s0与s1必然会有一个空间是空的。
例如:
minor gc 执行之后,剩下 A,B,C三个对象 A,B,C三个对象的年龄分别初始化为1放入到s0空间,则s1的空间是空的
当下一次执行Eden满了执行minor gc后,A,B,C三个对象会被复制到s1空间,并且三个对象的年龄加1,则为2,并且清空s0
之后会反复以上操作。
对象的年龄达到设定的一个值之后,会进入到老年代。
例如:当A,B,C对象的年龄都达到10之后,会进入到老年代当中。
3、Eden与Survivor的空间比例是8:1
也就是说 Eden占新生代的80%,s0与s1都占10%。因为年轻代的对象都是刚创建出来就会死的。也就是说新生代会一直由10%的空间的空着的
4、如果老年代空间满了之后会出发,全局垃圾回收 major gc 或 full gc
major gc:只回收老年代垃圾
full gc:回收老年代与新生代的垃圾
5、触发full gc时,就会触发STW(stop the world)现象,就是所有的进程都挂起,只等待full GC完成。所以要配置参数减少full gc的出现,否则程序会卡顿。
三、有关内存的常用配置参数
1、Heap Space 堆内存:使用 -Xms 、 -Xmx
-Xms:是在JVM启动时初始的Heap值,默认是系统物理内存的1/64但小于1G。默认当空余堆内存大于70%的时候,会减少到-Xms的值。
可通过-XX:MaxHeapFreeRation=来指定这个比例。但是我们一般不使用这个配置,我们一般会把-Xms与-Xmx设置为一样。这样可以避免JVM要重新分配内存,不会发生
内存抖动,也可以减少垃圾回收的次数。
-Xmx:JVM可申请的最大Heap值,默认是物理内存的1/4,但是小于1G,默认空余内存小于40%时,JVM会增大到-Xmx指定的值。
可在idea中加入JVM参数-Xms4g -Xmx4g -XX:+PrintGCDetails来查看GC的变化,可设置一样或者不一样的值查看结果。
-Xmn:设置新生代大小,Sun公司推荐是堆内存的3/8 例如:-Xmn2g
因为整个堆内存=新生代+老年代+永久代,也就是说新生代如果占用内存越大,老年大也就相应的缩小,会导致程序崩溃,所以这个值很重要。
说明:不是所有new出来的对象都会进入到新生代,也有可能直接进入到老年代。
例如:大对象:可通过设置-XX:PretenureSizeThreshold=1024单位为字节,也就是说当对象的大小超过1024字节的时候,会直接进入到老年代分配。
大的数组对象:但是数组中不可引用外部对象。如果老年代不够存放,会报错:OutOfMemoryError异常。
OutOfMemoryError异常:要么堆内存不够,要么存在内存泄漏
-XX:+MaxTenuringThreshold=10:代表新生代年龄到10后进入老年代,设置为0不会计算对象年龄,直接进入老年代。
2、Method Area 方法区:-XX:MaxPermSize或-XX:PermSize
-XX:PermSize:持久代初始化大小
-XX:MaxPermSize或:持久代初始化大小
设置成同样的值。一般设置为512m
3、Native Area 栈:-Xss
-Xss:每个线程的栈的大小,上面说过,一个线程建立一个栈,小系统推荐:128K 大系统:256K。
四、内存泄漏与内存溢出
1、内存泄漏 memory leak:指的是申请了一个内存空间后,无法释放,则称为内存泄漏,占着茅坑不拉屎
1、内存溢出 memory of memory 简称OOM:指的是堆内的剩余空间已经无法容纳新创建的数据时,会报出OOM异常。
例如:创建一个4M的数组,但是堆内剩余空间只剩3M,那么则会报错OOM