ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

对象分配过程及生命周期

2020-09-16 17:00:21  阅读:10  来源: 互联网

标签:生命周期 对象 开启 XX 线程 分配


一、对象分配流程图

 二、对象分配过程及生命周期详细流程

(1)JVM首先检查是否开启了栈上分配,如果开启,并且满足栈上分配的条件,则在栈上分配;否则,执行(3);

(2)栈上分配的对象,作用域结束之后出栈,生命周期结束,不需要GC;

(3)检查对象大小是否超过设定的大对象阈值,如果超过,则直接在老年代中申请内存进行分配;否则,执行(6);

(4)直接在老年代中分配的大对象,当老年代内存不够分配时,会触发Full GC,入股FGC之后内存还是不够分配,则会抛出OutOfMemoryError(内存溢出);

(5)大对象在老年代正常分配之后,如果一直被引用(强引用),则不会被垃圾回收,直到不再被引用,经过FGC之后结束生命周期;

(6)检查是否开启线程本地分配(TLAB:Thread Local Allocation Buffer),不管是否开启,都会在Eden(伊甸区)分配空间;

(7)当Eden的内存不足以容纳新的对象时,会触发一次Young GC,清除垃圾对象之后将仍然存活的对象转移到Survivor(存活区)的S0区;

(8)重复(7)直到S0空间也满了时,触发YGC回收Eden区和S0区,然后将这两个区域存活的对象拷贝到S1区(复制一次对象年轻加1),清空Eden和S0,然后交换S0和S1的位置;

(9)重复(8),在每次回收的时候会检查存活对象的年龄,如果达到了设定的阈值(CMS默认为6,其他为15),会进入老年代。

注:在这个过程中,S1区域的内存空间可能不足以容纳所有的存活对象,会通过空间担保和动态年龄直接把一部分对象直接放入到老年代,即使这个对象的年龄还没有达到设定的阈值;

三、栈上分配

在方法体内部声明的变量和或者创建的对象,如果不会作为返回值被其他线程访问,就不需要在堆内存(所有线程共享)分配,而是直接从该线程的栈空间分配内存;HotSpot默认是开启了栈上分配。

参数(只有同时开启标量替换和逃逸分析):

-XX:-DoEscapeAnalysis:取消逃逸分析

-XX:+DoEscapeAnalysis:开启逃逸分析(默认)

-XX:-EliminateAllocations:取消标量替换

-XX:+EliminateAllocations:开启标量替换(默认)

逃逸分析和标量替换可以参考其他文章。

优点:

直接在栈上分配的对象,只需要在当前线程的生命周期内入栈出栈,线程生命周期结束时,对象就出栈,生命周期结束,不需要GC介入进行回收,提高程序执行的效率。

四、TLAB(Thread Local Allocation Buffer),线程本地分配

由于堆是所有线程共享的,创建对象在堆中(主要是Eden区)分配内存时,那么所有线程可能会竞争同一块内存区域,JVM引入TLAB的,在堆中给每个线程分配一块私有的内存空间,当一个线程需要在堆上给对象分配内存时,只需要到自己对应的那一块区域分配,而不需要竞争,从而提高了效率。

TLAB默认是开启的,可以 通过参数-XX:+UseTLAB或-XX:-UseTLAB开启或禁用线程本地分配,建议开启。

标签:生命周期,对象,开启,XX,线程,分配
来源: https://www.cnblogs.com/merson1314/p/13680056.html

专注分享技术,共同学习,共同进步。侵权联系[admin#icode9.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有