目录
Permanent Generation(Metaspace)
Old Generation和MajorGC(FullGC)
元空间设置不当引起的频繁Full GC (Metadata GC Threshold)
-Xms, –Xmx, –Xss,-Xmn(-XX:newSize和-XX:MaxnewSize)
年轻代对象年龄阀值 -XX:MaxTenuringThreshold
元空间参数 XX:MetaspaceSize,-XX:MaxMetaspaceSize
JVM模型
方法区
又叫静态区,被所有的线程共享;方法区包含所有的class和static变量;方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
栈
Java中一个线程一个栈区,每一个栈中的元素都是私有的,不被其他栈所访问。栈有后进先出的特点,栈中的数据大小与生存期都是确定的,缺乏灵活性,但是,存取速度比堆要快,仅次于CPU中的寄存器。java中的8中基本数据类型,局部变量都是存在栈中,也可以理解为这些数据大小基本都是固定的。
堆
Java中只有一个堆,被所有线程共享。简单说就是new出来的对象和数组都存在堆中,大小是可以动态变化的,也正是因为这个原因导致堆中数据访问速度慢。垃圾回收机制检测到某对象未被引用时,则自动销毁该对象。java中的包装数据类型包括Byte、Short、Integer、Long、Float、Double、Boolean、Character这些数据类型都是存放在堆中的
在JDK8之前:Young Generation(Eden、From、To)、OldGeneration、Permanent Generation(JDK8以后改为Metaspace)。
Young Generation和MinorGC
Young Generation:指的是新生带,新生代存储的是新创建的对象。新生代分为较大的Eden空间和两份较小的Survivor空间,默认比例是8:1:1。JVM只会使用Eden和其中一块Survivor空间放新创建的对象,另一份用于GC。
MinorGC:当Eden和其中一块Survivor区空间不足时会触发Minor GC ,使用复制清除算法(Copinng算法),原因是年轻代每次GC都要回收大部分对象。MinorGC要做的事就是把存活的对象放到未使用的Survivor区空间中,清空Eden和刚才使用过的Survivor空间(第一次MinorGC只会清空Eden区)。
详细分析过程如下:首先新创建对象会被放在Eden区,当Eden区空闲不够大时JVM为新对象分配空间失败(Allocation Failure)引发第一次MinorGC,根据GC算法把存活的对象复制到Survivor中的其中一个S0区,清空了Eden区;然后新创建对象继续放入清空后的Eden区,当Eden区再次被占满之后引发第二次MinorGC,这时候会把Eden区和S0区存活下来的对象移到S1区,然后再继续把新创建的对象放入Eden区,当再次沾满后引发第三次MinorGC,这次会把Eden区和S1区存活的对象复制到S0区,就这样反复GC,每GC一次,对象的年龄就增加
一岁
,达到某个值后(15),对象会被复制到OldGeneration。新生代中最多只有一个S区被占用(第一次GC前两个都空闲),这种流程回收避免的全部区域回收,提高了效率。
Permanent Generation(Metaspace)
持久带,主要是存放方法区。JDK8以后,Oralce-Sun Hotspot中移除了持久代,用Metaspace代替,元空间的本质和永久代类似,都是对JVM规范中方法区的实现两者的区别是Metaspace是在系统本地内存,它不在于JVM内;
也就是这时候的JVM堆空间大小 = Young Generation + OldGeneration
使用Metaspace代替永久带的原因
永久带的初始化内存-XX:MaxPermSize可能不够用,又不易调整;
Metaspace不在JVM内,避免了GC时候的扫描;
Old Generation和MajorGC(FullGC)
Old Generation指的是老年代,正常情况下,老年代存放的一般是长期存活下来的对象(多次MinorGC后对象年龄达到指定阈值进入老年代))以及大对象(为了避免频繁复制,大对象会直接进入老年代),除此之外,如果survivor 区设置的太小<