引用别人的文章,一图胜千言:
对象分配流程图
1、依据逃逸分析,是否可以栈上分配?如果可以,则使用标量替换,把对象分配到栈空间上,如果线程销毁或方法调用结束后,自动销毁,不需要GC回收器介入。进行第3步操作。
2、不满足逃逸分析,判断对象是否是大对象?如果是,直接分配到堆上 Old Generation 老年代上。如果对象变为垃圾后,由老年代GC 收集器(比如 Parallel Old, CMS, G1)回收。不是大对象,则进行第3步操作。
3、判断是否可以在 TLAB中分配?如果是,在 TLAB中分配堆上Eden区。否则,在 TLAB外堆上的Eden区分配。
4、TLAB分配失败,在新生代分配对象。空间足够,直接进行分配,如果空间不够,先进行一次YGC,再看空间是不是满足。
5、在新生代分配对象失败,新生代分配失败进行一个老年代的分配,老年代如果没有足够内存进行fullgc,再次分配。
TLAB(Thread Local Allocation Buffer)
本地线程分配池,每个线程都会在内存申请一个小块的内存,如果new出来的对象大小线程申请的小内存可以分配,这样就快速分配对象,在线程创建之初就已经申请内存了。当申请的内存使用完进行一个同步再次申请一小块内存。TLAB主要是为了加速对象的分配。
由于对象一般分配在堆上,而堆是线程共用的,因此可能会有多个线程在堆上申请空间,而每一次的对象分配都必须线程同步,会使分配的效率下降。
考虑到对象分配几乎是Java中最常用的操作,因此JVM使用了TLAB这样的线程专有区域来避免多线程冲突,提高对象分配的效率。
局限性: TLAB空间一般不会太大(占用eden区),所以 大对象无法进行TLAB分配,只能直接分配到堆 Heap上。
对象分配方法
指针碰撞和空闲列表,区别在于内存是否规整,指针碰撞指的是把指针指向一块与对象对等的区域,空闲列表指的是堆内存维护一个内存空闲列表,对象进行分配时候从空闲列表中找一块能够放的下此对象的内存,分配完之后更新空闲列表,选择何种分配方法取决于gc回收器。
逃逸分析
测试堆空间常用jvm参数_小鲁班-JAVA开发-CSDN博客