首先,堆中的内存分为三个大块(java8是两个,持久代被干掉了),新生代和老年代,持久代,新生代为各种new出来的对象所在场所,老年代存放的是在多次GC都活下来的对象,持久代(也被称作方法区,存放各种静态文件,包括类,方法等)不会发生minor GC,当持久代满时,会触发full GC
java8中,持久代被替换成metaspcace,metaspace不会占用虚拟机内存,占用的是本地内存
(1.7及1.7之前的版本持久代存放的是对象的方法等信息,持久代是占用堆内存的,1.8之后转移到了metaspace,metaspace占用的是本地内存,不会占用堆内存,
类的元数据信息转移到Metaspace的原因是PermGen很难调整。PermGen中类的元数据信息在每次FullGC的时候可能会被收集,但成绩很难令人满意。
而且应该为PermGen分配多大的空间很难确定,因为PermSize的大小依赖于很多因素,比如JVM加载的class的总数,常量池的大小,方法的大小等)
新生代分为三个区域,eden(伊甸园),两个survivor区
老年代大多都是由标记整理,标记清除来整理空间
新生代比较有意思,他由于存放的一般都是比较新的对象,但一般对象的生命周期比较短,所以需要比较频繁的GC,但是呢,GC线程一启动,就会暂停其他线程,stop the world,所以就会有一个minior GC,来清理新生代
清理新生代使用的是复制算法,所有的新对象被生成在eden区,当eden区容量不够时,会触发minor GC,两个survivor区被分为From 和 To 区,触发minior GC时,eden区存活的大对象直接转移至老年代,不可达对象被直接清理,eden区剩余存活对象被转移至To区,From区存活的对象分两种情况,活过指定次数(可以设置)GC的对象会被转移到老年代,剩余存活对象也被转移到To区,minior GC结束时,From区是空的,下次执行minor GC时,From区和To区会互换身份
也就是说,每次minior GC结束后,总是有一个区是空的
需要注意的是,在minior GC过程中,如果To区满了,那么剩余本来会转移到To区的对象会被直接移到老年代,无论是否活过了指定次数的GC
而触发full GC的条件,就是年老代满时,或者方法区满时,或者调用System.gc(然而只是系统建议,并不一定会执行)