深入理解对象与垃圾回收机制

本文介绍了Java虚拟机中对象的内存分配方式,包括指针碰撞和空闲列表两种策略,这两种策略的选择取决于垃圾收集器是否带有压缩功能。接着,讨论了对象的组成部分,包括对象头、实例数据和对齐填充。对于对象不再被需要的判断,讲解了引用计数法和可达性分析算法,其中Java使用的是可达性分析。此外,还提到了如何通过finalize()方法抢救即将被回收的对象。
摘要由CSDN通过智能技术生成

先来问大家一个问题:虚拟机中对象分配内存的两种方式是什么?

虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。

在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需内存的大小在类加载完成后便可完全确定,为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来。假设Java堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”(Bump thePointer)。如果Java堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”(FreeList)。选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。因此,在使用Serial、ParNew等带Compact过程的收集器时,系统采用的分配算法是指针碰撞,而使用CMS这种基于Mark-Sweep算法的收集器时,通常采用空闲列表。
指针碰撞示例图:

 空闲列表示例图:

 再问一个问题:一个对象在JVM虚拟机中是有哪些部分组成的?

我估计很少有人会去思考这个问题。来看一张图:

 解释一下对齐填充吧,我们为了保证对象的内存规整,可以说是加一些无关紧要的数据,比如说凑成8个字节的整数倍(举个例子)。

讲完了对象的组成和内存分配方式,就要开始进入今天的主题,垃圾回收,这个垃圾很明显也是对象。我们如何判断一个对象不再被需要?目前主要有两种算法:

1.引用计数法

很简单,一个对象被引用一次,计数+1,如果计数为0,说明该对象不再有其他引用,就可以告诉垃圾回收器进行回收。但是引用计数法很明显存在一个问题,就是如果两个不需要的对象相互引用,那么这两个对象将永远无法被回收。

2.可达性分析(JVM采用的是这一种)

小提问:经过可达性算法,对象一定回收吗?

答案是否定的:我们来讲一个方法,一个抢救对象的方法。

finalize(),重写这个方法,可以在这个方法里面救活这个被回收的对象。

Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AD钙奶-lalala

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值