答案:不是!


:::warning 逃逸分析 ::: 逃逸分析,是一种可以有效减少Java 程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。通过逃逸分析,Java Hotspot编译器能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上。
在计算机语言编译器优化原理中,逃逸分析是指分析指针动态范围的方法,它同编译器优化原理的指针分析和外形分析相关联。当变量(或者对象)在方法中分配后,其指针有可能被返回或者被全局引用,这样就会被其他过程或者线程所引用,这种现象称作指针(或者引用)的逃逸(Escape)。

带来的好处:

  1. 堆分配对象变成栈分配对象。一个方法当中的对象,对象的引用没有发生逃逸,那么这个方法可能会被分配在栈内存上而非常见的堆内存上。
  2. 消除同步。线程同步的代价是相当高的,同步的后果是降低并发性和性能。逃逸分析可以判断出某个对象是否始终只被一个线程访问,如果只被一个线程访问,那么对该对象的同步操作就可以转化成没有同步保护的操作,这样就能大大提高并发程度和性能。
  3. 矢量替代。逃逸分析方法如果发现对象的内存存储结构不需要连续进行的话,就可以将对象的部分甚至全部都保存在CPU寄存器内,这样能大大提高访问速度。

:::warning TLAB ::: 我们都知道对象是在堆区中为对象分配内存,并且堆区被多个线程共享(JVM采用共享内存模型),当多个线程同时进行 new 操作时,需要通过同步操作保证数据的正确。在JVM虚拟中先尝试通过CAS操作为对象分配内存,如果分配不成功才会尝试获得堆区的锁,进行对象的分配。
通过同步操作虽然保证了内存分配的正确性,但是却限制了对象分配的效率,JVM通过TLAB来减少了同步的操作,TLAB全称是ThreadLocalAllocBuffer,这块内存是从堆空间中划分出来给线程管理。TLAB数据结构如下:

  1. class ThreadLocalAllocBuffer: public CHeapObj<mtThread> {
  2. HeapWord* _start; // address of TLAB
  3. HeapWord* _top; // address after last allocation
  4. HeapWord* _pf_top; // allocation prefetch watermark
  5. HeapWord* _end; // allocation end (excluding alignment_reserve)
  6. size_t _desired_size; // desired size (including alignment_reserve)
  7. size_t _refill_waste_limit; // hold onto tlab if free() is larger than this
  8. .....................省略......................
  9. }

TLAB空间主要有3个指针:_start、_top、_end。_start指针表示TLAB空间的起始内存,_end指针表示TLAB空间的结束地址,通过_start和_end指针,表示线程管理的内存区域;
当进行对象的内存划分的时候,就会通过移动_top指针分配内存(TLAB,Eden,To,From 区主要采用指针碰撞来分配内存(pointer bumping)),在TLAB空间为对象分配内存需要遵循下面的原则:

  1. obj_size + tlab_top <= tlab_end,直接在TLAB空间分配对象
  2. obj_size + tlab_top >= tlab_end && tlab_free > tlab_refill_waste_limit,对象不在TLAB分配,在Eden区分配。(tlab_free:剩余的内存空间,tlab_refill_waste_limit:允许浪费的内存空间)
  3. obj_size + tlab_top >= tlab_end && tlab_free < _refill_waste_limit,重新分配一块TLAB空间,在新的TLAB中分配对象

按照上面的规则,如果对象先TLAB划分失败,那么对象会在Eden空间划分对象,按原逻辑分配。