JVM对象的创建以及计数算法

虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。
对象所需内存的大小在类加载完成后便可完全确定,为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来。如果Java堆中内存是绝对规整,则使用“指针碰撞”。如果不规整,则使用“空闲列表”的内存分配方式。
指针碰撞:规整的内存中,用过的内存放一边,空闲的内存放另一边,中间放着一个指针作为分界点指示器,所分配内存就仅仅是把那个指针向空闲空间那边挪一段与对象大小相等的距离。
空闲列表:虚拟机需要维护一个列表,用于记录那些内存是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录。
因为虚拟机中创建对象是非常的频繁,所以在并发情况下不是线程安全的(指针正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的情况)。虚拟机采用了两种方案解决:CAS和本地线程分配缓冲区(TLAB)。
对象的对象头中存放了这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。
执行new指令之后会接着执行<init>方法,把对象按照程序猿的意愿进行初始化,这样一个真正可用的对象才算完全产生出来。
对象在内存中存储的布局可以分为3块区域:对象头、实例数据和对齐填充。
对象头包括两部分信息:第一部分用于存储对象自身的运行时数据,另一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
注意:并不是所有的虚拟机实现都必须在对象数据上保留类型指针。如果对象是一个Java数组,那在对象头中还必须有一块用于记录数组长度的数据。
建立对象是为了使用对象,我们的Java程序需要通过栈上的reference数据来操作堆上的具体对象。
如何通过reference数据定位对象的具体位置由具体的虚拟机去实现,主流的访问方式有使用句柄和直接指针。

通过句柄访问对象

通过直接指针访问对象

使用句柄:Java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄地址中包含了对象实例数据与类型数据各自的具体地址信息。
直接指针:Java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象地址。
虚拟机栈和本地方法栈溢出:

  • 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
  • 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。


栈容量只由-Xss参数设定。
String.intern()是一个Native方法,它的作用是:如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。
引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。
引用计算算法的实现简单,判定效率也很高,在大部分情况下它都是一个不错的算法。然而现在主流的Java虚拟机里面没有选用计数算法来管理内存,其中主要的原因是它很难解决对象之间相互循环引用的问题。
public class ReferenceCountingGC {
public Object instance = null;
private static final int _1MB = 1024*1024;

 

private byte[] bigSize = new byte[2*_1MB];

public static void testGC(){
ReferenceCountingGC objA = new ReferenceCountingGC();
ReferenceCountingGC objB = new ReferenceCountingGC();
objA.instance = objB;
objB.instance = objA;

objA = null;
objB = null;
System.gc();
}

public static void main(String[] args) {
testGC();
}
}

idea在vm options处加入-XX:+PrintGCDetails就可以打印出gc日志。
从运行结果可以清楚看到,GC日志中包含“8028K->560K",这意味着虚拟机并没有因为这两个对象互相引用就不回收它们。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值