栈上分配
依赖于线程的逃逸分析和标量替换
逃逸分析:当一个对象只存在于栈内,没有逃出栈,对象会在当前线程栈中分配空间
标量替换:类似int,boolean这种不可再被分割的成员变量,称为标量,反之则是聚合量,聚合量是由标量组成,当栈内空间没有足够连续空间以分配对象,会把聚合量分割为若干个标量,为每一个标量分配空间(标量所占空间远小于聚合量)
堆中分配
年轻代与老年代,年轻代:老年代=1:2,年轻代中eden:Survivor1:Survivor2=8:1:1
新建对象默认会被分配到年轻代的eden区,每做一次YoungGC/minorGC会将eden和Survivor2存活对象移到Survivor1中或者Survivor1移到Survivor2
大对象直接进入老年代:如果一个对象太大,放在eden区占用空间比较大,会频繁触发YoungGC,那么会考虑直接将他放到老年代,-XX:PretenureSizeThreshold=1000000 (单位是字节)用于设置直接进入老年代对象阈值,只有serial和parNew有效
长期存活的对象直接进入老年代,长期存活的对象考虑到一定分代年龄之后直接进入老年代,而不是一直在年轻代占用空间触发GC,默认分代年龄超过15会进入老年代,-XX:MaxTenuringThreshold:10用于设置进入老年代年龄阈值
对象年龄动态判断,当前放对象的Survivor区域里(其中一块区域,放对象的那块s区),一批对象的总大小大于这块Survivor区域内存大小的 50%(-XX:TargetSurvivorRatio可以指定),那么此时大于等于这批对象年龄最大值的对象,就可以直接进入老年代了, 例如Survivor区域里现在有一批对象,年龄1+年龄2+年龄n的多个年龄对象总和超过了Survivor区域的50%,此时就会 把年龄n(含)以上的对象都放入老年代。这个规则其实是希望那些可能是长期存活的对象,尽早进入老年代。对象动态年 龄判断机制一般是在minor gc之后触发的。
老年代内存担保机制,年轻代每次minor gc之前JVM都会计算下老年代剩余可用空间 如果这个可用空间小于年轻代里现有的所有对象大小之和(包括垃圾对象) 就会看一个“-XX:-HandlePromotionFailure”(jdk1.8默认就设置了)的参数是否设置了 如果有这个参数,就会看看老年代的可用内存大小,是否大于之前每一次minor gc后进入老年代的对象的平均大小。 如果上一步结果是小于或者之前说的参数没有设置,那么就会触发一次Full gc,对老年代和年轻代一起回收一次垃圾, 如果回收完还是没有足够空间存放新的对象就会发生"OOM" 当然,如果minor gc之后剩余存活的需要挪动到老年代的对象大小还是大于老年代可用空间,那么也会触发full gc,full gc完之后如果还是没有空间放minor gc之后的存活对象,则也会发生“OOM”