Java中,对象的创建与销毁无时无刻不在进行之中,但是在虚拟机中,对象的创建是再怎么样的?(除开数组,因为数组直接在堆上分配;除开Class对象,详情见我的blog,Java中的Class对象。)
JVM中对象的创建过程
当JVM遇到一个new的指令时,首先回去常量池中定位到一个类的符号引用。,并且检查类的符号引用代表的类是否已经被加载、链接、初始化过。如果没有,则先进行相应的类加载过程。
当类加载检查通过后,JVM开始为对象分配内存。大小在类加载完后已经确定。此时,如何分配内存在这里可以探讨一下。
方法一:指针碰撞,java堆中的内存绝对规整,使用的放在一边,空闲的放在一边。他们之间放一个指针做指示器,分配时内存向未使用过的内存偏移。
方式二:空闲列表,已使用和空闲内存交叉,JVM维护一张表,记录那些内存已经使用。在分配时,从列表中找出一块足够大的空间,并跟新记录。
为什么会存在这两种方式,这是和垃圾回收采用的算法相关的。详情请参阅我的博文----Java的垃圾回收机制。
如果你看完觉得分配没问题了,就大错特错了。考虑一下多线程的问题:
当你正在在为对象A分配一块内存时,指针还未修改;此时为对象B也分配到了这块内存怎么办?为了解决此问题,由于多线程造成的问题。虚拟机采用CAS失败重试的方法进行保证更新的原子性:另一种方式,每个线程在java堆中都预先分配一小块内存,哪个线程需要分配内存,就在哪个线程所被分配的内存重分配。当此内存使用完,进行同步锁定。
JVM中对象的内存布局
对象在内存的存储布局可以分为3块区域:对象头、实例数据和对齐填充
对象头包括两部分信息:1>.对象运行时自身的数据,比如HashCode、GC分带年龄等。 2.>类型指针。指向它类元数据的指针。
实例数据:程序代码中所定义的各种类型字段的内容。
对齐填充:占位符的作用。因为VM要求对象其实地址必须是8字节的整数倍。
JVM中对象的访问定位
Java程序需要通过栈上reference数据来操作对上的具体对象。目前主流的访问方式有句柄和直接指针。
直接指针:reference中存放的是对象地址。直接可以访问。
句柄(类型两级指针):Java堆中划分一块内存作为句柄池,reference存放的是对象的句柄地址,而句柄对象中存放了对象实录数据与数据类型个自己的地址。