JVM对象创建与内存分配
2021-07-21 20:22:05 0 举报
JVM对象创建与内存分配
作者其他创作
大纲/内容
对象
end
minor gc之前
带来的问题
TLAB(默认)
去常量池寻找对应类的符号引用没有被加载
老年代所剩空间>年轻代里面的所有对象
空闲空间
OOM
Y
栈内分配?
2.可达性分析算法:将“GC Roots” 对象作为起点,\t从这些节点开始向下搜索引用的对象,找到的对象都标记为非垃圾对象,其余未标记的对象都是垃圾对象GC Roots根节点:线程栈的本地变量、静态变量、本地方法栈的变量等等
对象内存
N
加载
初始化(设置默认值)
解析
属性赋值并执行构造方法
指针碰撞(如果Java堆中内存是绝对规整的)
CAS:虚拟机采用CAS配上失败重试的方式保证更新操作的原子性来对分配内存空间的动作进行同步处理
Eden
2.在并发情况下, 可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的情况。
full gc
进行标量替换:通过逃逸分析确定该对象不会被外部访问,并且对象可以被进一步分解时,JVM不会创建该对象,而是将该对象成员变量分解若干个被这个方法使用的成员变量所代替,这些代替的成员变量在栈帧或寄存器上分配空间,这样就不会因为没有一大块连续空间导致对象内存不够分配。开启标量替换参数(-XX:+EliminateAllocations),JDK7之后默认开启
是否能存下
分配内存
触发动态年龄判断机制
2.长期存活的对象将进入老年代(在Survivor区达到设置对应的age就移到老年代)
大对象?
S1
3.对象动态年龄判断:Survivor区域里现在有一批对象,年龄1+年龄2+年龄n的多个年龄对象总和超过了Survivor区域的50%,此时就会把年龄n(含)以上的对象都放入老年代。这个规则其实是希望那些可能是长期存活的对象,尽早进入老年代。对象动态年龄判断机制一般是在minor gc之后触发的。
老年区(old)
minor gc
标量与聚合量:标量即不可被进一步分解的量,而JAVA的基本数据类型就是标量(如:int,long等基本数据类型以及reference类型等),标量的对立就是可以被进一步分解的量,而这种量称之为聚合量。而在JAVA中对象就是可以被进一步分解的聚合量。
:内存中原有的对象
符合条件
初始化
准备:给静态变量分配内存,并设置默认值
对象创建
虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头Object Header之中。
判断类是否加载
记录空闲的 内存信息,当分配内存的时候就会从这里进行比对分配,再更新列表
对象内存回收
栈
是
在栈帧或寄存器上分配空间
解析:把符号应该替换为直接引用,会把一下静态方法引用指向内存的指针(静态链接),而动态链接是运行期间把符号引用替换直接引用
内存如何划分:1.指针碰撞(默认)2.空闲列表
判断哪些对象已经死亡
类加载
逃逸分析(1.7h后默认开启)
:新划分的内存
准备
8:1:1
老年代空间分配担保机制:年轻代每次minor gc之前JVM都会计算下老年代剩余可用空间如果这个可用空间小于年轻代里现有的所有对象大小之和(包括垃圾对象)就会看一个“-XX:-HandlePromotionFailure”(jdk1.8默认就设置了)的参数是否设置了如果有这个参数,就会看看老年代的可用内存大小,是否大于之前每一次minor gc后进入老年代的对象的平均大小。如果上一步结果是小于或者之前说的参数没有设置,那么就会触发一次Full gc,对老年代和年轻代一起回收一次垃圾,如果回收完还是没有足够空间存放新的对象就会发生\"OOM\"当然,如果minor gc之后剩余存活的需要挪动到老年代的对象大小还是大于老年代可用空间,那么也会触发full gc,full gc完之后如果还是没有空间放minor gc之后的存活对象,则也会发生“OOM”
Young GC
:维护的指针
类加载完成就可以知道内存大小,就会从heap中划分出来。
空闲列表(如果Java堆中的内存并不是规整的,已使用的内存和空 闲的内存相互交错)
执行init()方法
:空闲内存
1.引用计数法:给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加1;当引用失效,计数器就减1;任何时候计数器为0的对象就是不可能再被使用的。这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间相互循环引用的问题。 所谓对象之间的相互引用问题,如下面代码所示:除了对象objA 和 objB 相互引用着对方之外,这两个对象之间再无任何引用。但是他们因为互相引用对方,导致它们的引用计数器都不为0,于是引用计数算法无法通知 GC 回收器回收他们。给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加1;当引用失效,计数器就减1;任何时候计数器为0的对象就是不可能再被使用的。这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间相互循环引用的问题。 所谓对象之间的相互引用问题,如下面代码所示:除了对象objA 和 objB 相互引用着对方之外,这两个对象之间再无任何引用。但是他们因为互相引用对方,导致它们的引用计数器都不为0,于是引用计数算法无法通知 GC 回收器回收他们。
JVM
本地线程分配缓冲(TLAB):把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存。通过-XX:+/-UseTLAB参数来设定虚拟机是否使用TLAB(JVM会默认开启-XX:+UseTLAB),-XX:TLABSize 指定TLAB大小。
new A()
new 对象
是否配合参数
验证
验证:校验字节码文件是否正确
对象过早进入老年代的情况:
1.内存如何划分
内存够分配
类加载检查
AGE?
老年代所剩空间>历史每一次minor gc后存放到老年代大小
进行标量替换(1.7后默认)
初始化:静态变量的默认值设置为指定值,并执行静态代码块
解决并发问题的方法:
Free Lis
设置对象头
1.大对象直接进入老年代(避免为大对象分配内存时的复制操作而降低效率。)
S0
收藏
收藏
0 条评论
下一页