JVM堆内存划分
逻辑上分为3区:
- 新生代Young Gen
- 伊甸园区 --Eden
- 幸存者0区 --S0/from
- 幸存者1区 --S1/to
- 默认比例 eden:S0:S1=8:1:1
- 老年代Old Gen
- 元空间(jdk7:永久区)Perm Gen
物理上分为:新生代+老年代
新生代:老年代 = 1 :2;
堆new对象流程
新生区是对象的创建,成长,销毁的区域,一个对象在这里产生,应用,然后被GC(垃圾回收器)收集,结束生命;所有的类都是在新生代内的eden区被new的,幸存者有两个区,S0(又称from区),S1(又称to区);当eden区快 用完时,将进行一次垃圾回收,为MinorGC(轻量级的垃圾回收器),将新生代区,没有被引用的对象进行销毁,随后eden区的剩余对象,将升级机制,eden–》S0;若该对象经历了15次的垃圾回收机制,还没有被销毁,将进入老年代,若老年代区域内存快满,将进行FullGC(重量级),若执行了FullGC后依然发现无法进行对象的保存,将抛出OOM错误(Out Of Memory);
MinorGC原理
from区和to区,这两个区域位置和名次不固定,每次GC后互换,谁空谁是to区
GC过程(复制–清空—交换)
- eden区第一次满触发MinorGC;
- 还存活的对象复制到From区;/也可理解为到to区(因为此时from 和 to 内存都为0,没有严格的区分,谁空谁是to区)
- 清空eden区
- 当eden区再次出发GC,扫描eden和from区,一起回收
- 存活的对象复制到to区(to区为0),年龄+1(若年龄符合,此时升级为老年代)
- 清空eden和from区
- 此时from区清空变为to区,to区有存活存活成为from区;
- 直到年龄15,升级为老年代
永久代
经研究和统计:98%的对象为临时对象,即只在eden区活动
实际而言:方法区和堆一样。是各个线程共享的内存区域,它用来存储虚拟机加载的,类信息+普通常量+编译器编译后的代码等等,虽然JVM规范把方法区描述成堆的一个逻辑部分,但它还有一个别名no-heap(非堆),目的是把它和heap分开;
对于hotspot虚拟机而言,很多开发者习惯把方法区成为永久代,但严格意义上讲两者是不同的,或者说使用永久代来实现方法区,永久代是方法区(理解为接口)的实现;jdk1.7中,已经把原在永久代的字符常量池移走;
永久代:
是一个常驻内存的区域,用来存放JDK自身携带的Class,interface的元数据,也就是它存储的是运行环境所必须的类信息,该区域不会被GC所清除,关闭JVM才会被释放;
堆参数调优
以JDK1.8+hotspot为例
JDK7:
-Xx:Permisize :调整永久代的空间
JDK8:
永久代移除,元空间代替,
永久代和元空间的最大区别:
永久代使用的JVM的堆内存,但是元空间使用的空间,并不属于JVM范畴,而是使用本机物理内存,因此元空间大小受本地内存限制,类的元数据放入native memory,字符串和类的静态变量放入堆中,这样可以加载多少类的元数据不再由JDK1.7的MaxPermiSize控制,而由系统实际可用空间来控制;
-xms:设置初始分配大小,默认物理内存的“1/64”;
-xmx:最大分配内存,默认物理内存的“1/4”;
-XX:printGCDetails:输出GC的详细日志;
Runtime类:对应JVM runtime
public static void main(String[] args) {
System.out.println(Runtime.getRuntime().availableProcessors());
System.out.println("xms:"+Runtime.getRuntime().totalMemory()/1024/1024+"Mb");
System.out.println("xmx:"+Runtime.getRuntime().maxMemory()/1024/1024+"Mb");
}
最好xms和xmx设置为一样,避免频繁开辟内存空间所带来的资源消耗,避免内存忽高忽低;同时在判断gc是否运行时,gc和开辟内存相互竞争,导致程序异常
idea中配置jvm参数
gc运行解析
运行下列代码
public static void main(String[] args) {
String str = "test";
while (true){
str += str +new Random().nextInt(88888)+new Random().nextInt(9999999);
}
}
调节jvm参数
-Xms10m -Xmx10m -XX:+PrintGCDetails
报错:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
观察GC日志
结论:开始minor GC,随后FullGC,最后FullGC也没法开辟空间---->报错