wangzhenhui1991 / Notes

3 stars 0 forks source link

JVM:Java 对象具体是如何创建的 #9

Open wangzhenhui1991 opened 7 years ago

wangzhenhui1991 commented 7 years ago

前言

想到一个问题就是对象是如何创建的,那么直接反应就是 new 啊,但是再具体的细节倒有点记不得,翻看了《深入理解Java虚拟机》,以及参考 Java中的逃逸分析和TLAB以及Java对象分配 ,做下总结。

Java对象是如何创建

  1. New对象:当我们使用 new 的时候。首先虚拟机会检查该类有没有被加载,如果已经被加载了,那么就能够确定下所需要分配的内存空间的大小。

  2. 分配方式:虚拟机在堆内存中进行分配的时候,有两种方式:

    • 指针碰撞 :用了的内存放在一边,那么用了的内存和没用的内存中间会有一个指针,然后分配内存的时候直接移动该指针即可。
    • 空闲列表 :用的内存和没用的内存交错着,这个时候需要虚拟机维护一个空闲列表,然后分配内存的时候就从空闲列表中选取一个内存区域进行分配,最后更新列表。

      那么具体用哪种方式是由 垃圾回收器进行决定, 比如说 Serial,ParNew这种回收器使用的就是指针碰撞的方式(也就是带了压缩功能的)。像 CMS 这种垃圾回收器就使用 空闲列表的方式。

    分配内存中多线程问题

    那么在分配内存的时候,可能会出现多线程问题,解决方式有 CAS 乐观锁,以及 TLAB方式。TLAB的全称是 Thread Local Allocation Buffer。 TLAB 每个线程 JVM在内存新生代Eden Space中开辟了一小块线程私有的区域,称作TLAB(Thread-local allocation buffer)。默认设定为占用Eden Space的1%。在Java程序中很多对象都是小对象且用过即丢,它们不存在线程共享也适合被快速GC,所以对于小对象通常JVM会优先分配在TLAB上,并且TLAB上的分配由于是线程私有所以没有锁开销。因此在实践中分配多个小对象的效率通常比分配一个大对象的效率要高。

也就是说,Java中每个线程都会有自己的缓冲区称作TLAB(Thread-local allocation buffer),每个TLAB都只有一个线程可以操作,TLAB结合bump-the-pointer技术可以实现快速的对象分配,而不需要任何的锁进行同步,也就是说,在对象分配的时候不用锁住整个堆,而只需要在自己的缓冲区分配即可。

  1. 初始化:以上说到 具体虚拟机是如何分配出一块内存的,那么分配完之后,虚拟机层面上首先要进行初始化,这样即使我们代码中不初始化,也可以使用默认值。虚拟机全部赋0初始化之后,就轮到了我们代码层面上的初始化,比如说构造函数中我们自定义的初始化。

这两部做完之后,整个对象的创建就算完成了。

Java对象是如何定位

定位的方式也分为两种: