Java基础知识点总结系列(九)—— 指针碰撞与TALB

一、 Java中的指针碰撞与TLAB

1. 指针碰撞

Java中提到指针碰撞主要是在GC中,GC的标记/整理(标记/压缩)算法在每次执行完之后会通过一个指针将堆内存分为两个区域,分别是已用区域和未用区域。指针的左边已用区域内部存满了对象(其实就是经过上一次GC之后存活下来的对象),指针的右边为可用区域。之后当需要new一个对象时,JVM会在当前指针所指位置为新对象分配内存,并将指针向后移动对象所对应size位。比如一个new的对象需要128字节的内存空间,那么JVM将会从当前指针所指位置开始,之后的128字节分配给该对象,同时指针后移128个字节。但由于堆内存本身是线程共享的,在多线程场景下,当一个线程需要创建对象,这时指针还没来得及修改(指针是在新对象占完位之后才能进行修改),如果另一个线程也需要分配空间,就会造成两个对象空间冲突,这就称之为指针碰撞。那如何解决呢?
在这里插入图片描述

2. TLAB(Thread Local Allocation Buffer 线程本地分配缓存区)

2.1 TALB的思路

TALB的解决思路比较简单粗暴,既然是因为堆内存多线程共享引发了问题,那我就直接给每个线程一个私有的区域分配对象不就解决了吗?

2.2 TALB的原理

TALB就是在堆内存上额外为每个线程分配一块线程私有区域,其大小一般比较小,默认占Eden区的1%。其本质就是通过start、top、end三个指针实现,其中start和end分别指向这个TALB的开始和结尾位置,用于确定该TALB在堆上对应区域,避免其他线程再过来分配内存,top实时指向TALB区域内当前可分配的第一个位置,当一个TALB满了或剩余空间不足以存储新申请的对象时,线程会向JVM再申请一块TALB。到这里为止,指针碰撞多线程问题似乎已经得到了解决,不过由于TALB空间本身较小(默认只占Eden区1%),所以就很容易出现TALB剩余区域不足以存储新对象的情况,这时线程会把新对象存到新申请的TALB中,这样原有的TALB中剩余区域就会被浪费,造成内存泄漏。那么如何解决内存泄漏呢?

2.3 最大浪费空间

由于TALB内存浪费现象较为严重,所以JVM开发人员提出了一个最大浪费空间对TALB进行约束。
当TALB剩余空间存不下新对象时,会进行一个判断:
① 如果当前TALB剩余空间小于最大浪费空间,则TALB所属线程会向JVM申请一个新的TALB区域存储新对象,如果依旧存储不下,则对象会放在Eden区创建。
② 如果当前TALB剩余空间大于最大浪费空间,则对象直接去Eden区创建。

2.4 TALB的局限性

虽然TALB解决了指针碰撞在多线程场景下的问题,并且通过最大浪费空间可以减少内存泄漏,但其本身依旧有一些缺点:
① GC更频繁: 由于每个TALB所占用的空间都要比线程实际需要的空间大小大一些(因为不可能每个TALB都刚好存满,也就是TALB空间浪费更严重),所以一批对象直接存储在Eden区会比存储在TALB区占用更少的空间,进而容易引发Minor GC。
② TALB允许内存浪费,会导致Eden区内存不连续。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值