对象创建(new一个对象)
大黄 Lv4

创建一个对象的流程

对象创建 流程.jpg

这边着重讲几个东西

一个对象在创建前就已经知道会占用多大的空间

关于分配内存时候的并发问题

关于分配内存的并发问题,需要从垃圾回收器等方面考虑

首先先介绍两个概念,指针碰撞与空闲列表

假如我们的回收算法,在回收对象的时候还会有整理的功能,那么我们对中的内存始终是一块未使用,一块已使用的。然后他们中间放着一个指针作为分界点。每次分配空间就是将指针往空闲空间挪动指定大小

但是有些垃圾回收器并不会去做整理,此时就会产生很多不连续的空闲内存空间。对于这种,虚拟机就需要维护一个列表,来记录那些空闲空间。然后在分配对象需要申请空间的时候,就会去空闲列表上找出足够大的空间分配给对象实例

对应的一些使用场景

以Serial、ParNew等带有压缩整理过程的收集器,系统采用的是指针碰撞,即简单又高效

对于CMS这种基于清除(Sweep)算法的收集器,需要空闲列表来分配内存

说完了分配空间,回到一开始并发问题。分配空间是的并发问题指的是:

线程A在给对象A分配内存时,还未来得及将指针指向内存空间,此时线程B进来给对象B分配内存,重复使用了这块内存空间。

对此,虚拟机有两种方式解决:

  • CAS+失败重试
  • 把内存分配的操作按照线程划分在不同的空间上进行(即每个线程在Java堆中实现分配一小块内存 本地线程分配缓冲) TLAB
    • 会将赋零值的操作在这一步就完成

句柄访问,直接指针的优缺点在哪里

句柄访问:Java堆中会额外划分出一块内存作为句柄池,reference中存储的就是对象的句柄地址,句柄中包括了对象实例数据与类型数据格子具体的地址信息

优点:因为垃圾回收时移动对象是一个很普遍的行为,在移动对象时我们只需要改变句柄中的实例数据的指针,不需要逐个修改reference

但是访问时会多加一次句柄池的访问,效率会较直接指针低一点

对象创建 通过句柄访问对象.png

直接指针:堆中对象实例数据会保留对象类型数据的地址信息

对象创建 直接链接对象.png

对象头

对象在堆内存中存储布局分为三个部分:对象头、实例数据、对齐填充

对象创建 对象头.png

  • Post title:对象创建(new一个对象)
  • Post author:大黄
  • Create time:2021-12-30 22:01:35
  • Post link:https://huangbangjing.cn/2021/12/30/对象创建(new一个对象)/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.