当前位置:主页 > 最新源码
JVM源码分析之线程局部缓存TLAB
日期:2017-05-30 浏览量:

  介绍TLAB之前先思考一个问题:

  创建对象时,需要在堆上申请指定大小的内存,如果同时有大量线程申请内存的话,可以通过锁机制或者指针碰撞的方式确保不会申请到同一块内存,在JVM运行中,内存分配是一个极其频繁的动作,这种方式势必会降低性能。

  因此,在Hotspot 1.6的实现中引入了TLAB技术。

  什么是TLAB

  TLAB全称ThreadLocalAllocBuffer,是线程的一块私有内存,如果设置了虚拟机参数 -XX:UseTLAB,在线程初始化时,同时也会申请一块指定大小的内存,只给当前线程使用,这样每个线程都单独拥有一个Buffer,如果需要分配内存,就在自己的Buffer上分配,这样就不存在竞争的情况,可以大大提升分配效率,当Buffer容量不够的时候,再重新从Eden区域申请一块继续使用,这个申请动作还是需要原子操作的。

  TLAB的目的是在为新对象分配内存空间时,让每个Java应用线程能在使用自己专属的分配指针来分配空间,均摊对GC堆(eden区)里共享的分配指针做更新而带来的同步开销。

  TLAB只是让每个线程有私有的分配指针,但底下存对象的内存空间还是给所有线程访问的,只是其它线程无法在这个区域分配而已。当一个TLAB用满(分配指针top撞上分配极限end了),就新申请一个TLAB,而在老TLAB里的对象还留在原地什么都不用管——它们无法感知自己是否是曾经从TLAB分配出来的,而只关心自己是在eden里分配的。

  TLAB实现

  实现位于/Users/zhanjun/openjdk/hotspot/src/share/vm/memory/threadLocalAllocBuffer.hpp

  

JVM源码分析之线程局部缓存TLAB

  TLAB简单来说本质上就是三个指针:start,top 和 end,每个线程都会从Eden分配一大块空间,例如说100KB,作为自己的TLAB,其中 start 和 end 是占位用的,标识出 eden 里被这个 TLAB 所管理的区域,卡住eden里的一块空间不让其它线程来这里分配。

  而 top 就是里面的分配指针,一开始指向跟 start 同样的位置,然后逐渐分配,直到再要分配下一个对象就会撞上 end 的时候就会触发一次 TLAB refill,refill过程后续会解释。

  _desired_size 是指TLAB的内存大小。

  _refill_waste_limit 是指最大的浪费空间,假设为5KB,通俗一点讲就是:

  1、假如当前TLAB已经分配96KB,还剩下4KB,但是现在new了一个对象需要6KB的空间,显然TLAB的内存不够了,这时可以简单的重新申请一个TLAB,原先的TLAB交给Eden管理,这时只浪费4KB的空间,在_refill_waste_limit 之内。

  2、假如当前TLAB已经分配90KB,还剩下10KB,现在new了一个对象需要11KB,显然TLAB的内存不够了,这时就不能简单的抛弃当前TLAB,这11KB会被安排到Eden区进行申请。

  在Java代码中执行new Thread()的时候,会触发以下代码

  

JVM源码分析之线程局部缓存TLAB

  JavaThread的run方法中,第一步就是调用this->initialize_tlab();方法初始化TLAB,initialize_tlab实现如下:

  

JVM源码分析之线程局部缓存TLAB

  其中tlab()返回的就是一个ThreadLocalAllocBuffer对象,调用initialize()初始化TLAB,实现如下:

  

JVM源码分析之线程局部缓存TLAB

  1、设置当前TLAB的_desired_size,该值通过initial_desired_size()方法计算;

  2、设置当前TLAB的_refill_waste_limit,该值通过initial_refill_waste_limit()方法计算;

  3、初始化一些统计字段,如_number_of_refills、_fast_refill_waste、_slow_refill_waste、_gc_waste和_slow_allocations;

  字段_desired_size的计算过程分析

  

JVM源码分析之线程局部缓存TLAB

  TLABSize在argument模块中默认会设置大小为 256 * K,也可以通过JVM参数选择进行设置,不过即使设置了也会和一个最大值max_size进行比较,然后取一个较小值,其中max_size计算如下:

  

JVM源码分析之线程局部缓存TLAB

  这里明确说明了TLAB的大小不能超过可以容纳 int[Integer.MAX_VALUE],有点疑惑,why?

  字段_refill_waste_limit计算分析

  计算逻辑很简单,其中TLABRefillWasteFraction默认 64

  内存分配

  new一个对象,假设需要1K的大小,我们一步一步看看是如何分配的。

  

JVM源码分析之线程局部缓存TLAB

  对象的内存分配入口为instanceKlass::allocate_instance(),通过CollectedHeap::obj_allocate()方法在堆内存上进行分配

  

JVM源码分析之线程局部缓存TLAB

  其中common_mem_allocate_init()方法最终会调用CollectedHeap::common_mem_allocate_noinit()方法,实现如下:

  

JVM源码分析之线程局部缓存TLAB

相关文章:
·《LOL》新皮肤源代码 黑默丁格皮肤预览
·《LOL》新皮肤源代码 伊莉丝皮肤预览
·《LOL》新皮肤源代码 卡莉斯塔皮肤预览
·Facebook重磅发布ParlAI,重塑机器对话新格局(附源
·微软新论文:如何利用深度特征流提高视频识别
→ 特别推荐
《LOL》新皮肤源代码
《LOL》新皮肤源代码
《LOL》新皮肤源代码
Facebook重磅发布ParlA
微软新论文:如何利
最新版微信收银系统
小白学源码审计-3
JVM源码分析之线程局
苹果发布macOS Sierra最
《英雄联盟》最新女
曹毅:源码资本的“
2017最新代码托管服务
众筹平台Kickstarter宣布
LOL新英雄卡蜜尔技能
htc vive前置摄像头 如
→ 热点TOP10
11月12日最新江
软件:唯有安
LUPA开源周刊:
svn实现垃圾清
开放源码在大
南京程序员用
最新微博士仿
胜思网络正式
Zephyr 操作系统
滴滴出行等i

友情链接/网站合作咨询: