堆内存分配:
- 新生代-1/3
- Eden区 8/10
- From Survivor 1/10
- To Survivor 1/10
- 老年代-2/3
为什么有 From和To,2块区域? 因为新生代的垃圾回收算法:标记-复制算法
把内存区域分为两块,每次使用一块,GC的时候把一块中的内容移动到另一块中,原始内存中的对象就可以被回收了
假如总heap(堆) max分配1200M,那么年轻代占用1/3就是400M,老年代占2/3就是800M。
Eden占年轻代的8/10就是320M。Survivor占年轻代的2/10就是80M,from和to各占40M。
这样划分的目的是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收。
永久代是指的方法区!!!
- 新生代:主要是用来存放新生的对象
- 老年代:存放生命周期比较长,大小较大的对象
新创建的对象都会被分配到Eden区(如果该对象占用内存非常大,则直接分配到老年代区), 当Eden区内存不够的时候就会触发MinorGC(Survivor满不会引发MinorGC,而是将对象移动到老年代中)
1.在Minor GC 开始 的时候,对象只会存在于Eden区和From Survivor区,To Survivor区是空的。Minor GC操作后,Eden区如果仍然存活的对象,将会被复制到Survivor To区,并清除内存。而From区中,对象在Survivor区中每熬过一次Minor GC,年龄就会+1岁,当年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置,默认是15)的对象会被移动到年老代中,否则对象会被复制到“To”区。经过这次GC后,Eden区和From区已经被清空。
在发生一次Minor GC后,from区就会和to区互换,原Survivor To成为下一次GC时的Survivor From区。
总结: 在发生Minor GC时,Eden区和Survival From区会把一些仍然存活的对象复制进Survival To区,并清除内存。Survival to区会把一些存活得足够旧的对象移至年老代。总之,GC后,都会保证Survivor To区是空的。
2.随着Minor GC的持续进行,老年代中对象也会持续增长,导致老年代的空间也会不够用,最终会执行Major GC,回收年老代和年轻代中不再被使用的对象资源。
3.当老年代也满了装不下的时候,就会抛出OOM(Out of Memory)异常。
4.Full GC是清理整个堆空间—包括年轻代和老年代。什么时候触发:
-
调用System.gc
-
方法区空间不足
-
老年代空间不足,包括:
新创建的对象都会被分配到Eden区,如果该对象占用内存非常大,则直接分配到老年代区,此时老年代空间不足。
做Minor GC操作前,发现要移动的空间(Eden区、From区向To区复制时,To区的内存空间不足)比老年代剩余空间要大,则触发Full GC,而不是Minor GC等等
- 老年代使用的算法是:(Parallel Old)采用的是标记整理,(CMS)采用的是标记清除
- 新生代一般使用标记复制
小总结:
-
Minor GC是发生在新生代中的垃圾收集,采用的标记-复制算法;
-
新生代中每次使用的空间不超过90%,主要用来存放新生的对象;
-
Minor GC每次收集后Eden区和一块Survivor区都被清空;
-
Major GC是发生在老年代中的垃圾收集,采用的标记-清除 / 标记-整理算法