学习小记 -- JVM堆一定是线程共享的吗?

今天的第三份学习笔记~~~~翻身做主人真不容易啊!

我们都知道,在JVM内存模型中,堆是运行时数据区的一部分,里面存放所有的对象实例以及数组都要在堆上分配,是线程共享的,但是!!!它是处处共享吗?大佬告诉我不是!好吧,快快记下来,学习了~

大佬先问了:Java对象的内存分配过程是如何保证线程安全的?

我:啊。。这。。不知道🤷‍♂️。。。

Java对象的内存分配,主要是对象的引用指向这个内存区域,然后进行初始化操作。因为堆是全局共享的,因此在同一时刻,很可能会有多个线程创建对象,有可能会出现指向同一内存区域的情况,这就造成了不安全,那么如何才能保证线程安全呢??

在HotSpot是通过TLAB(Thread Local Allocation Buffer),线程本地分配缓存区实现的。

TLAB:

TLAB是虚拟机在堆内存的eden划分出来的一块专用空间,是线程专属的。在虚拟机的TLAB功能启动的情况下,在线程初始化时,虚拟机会为每个线程分配一块TLAB空间,只给当前线程使用,这样每个线程都单独拥有一个空间,如果需要分配内存,就在自己的空间上分配,这样就不存在竞争的情况,可以大大提升分配效率。

注:我们说TLAB是线程独享的,但是只是在“分配”这个动作上是线程独享的,至于在读取、垃圾回收等动作上都是线程共享的。而且在使用上也没有什么区别

也就是说,虽然每个线程在初始化时都会去堆内存中申请一块TLAB,并不是说这个TLAB区域的内存其他线程就完全无法访问了,其他线程的读取还是可以的,只不过无法在这个区域中分配内存而已。

并且,在TLAB分配之后,并不影响对象的移动和回收,也就是说,虽然对象刚开始可能通过TLAB分配内存,存放在Eden区,但是还是会被垃圾回收或者被移到Survivor Space、Old Gen等。

TLAB空间的内存也非常小,默认情况下仅占有整个Eden空间的1%。所以如果有大对象,会直接在eden区或老年代分配,但这这种情况下就要进行同步控制了(CAS),小的对象比大的对象分配起来更加高效。

缺点:

因为TALB的空间有限,所有当一个新计算出来的对象大小超过TALB的剩余空间时,有两种处理办法:

  1. 直接在堆内存中对该对象进行内存分配。
  2. 废弃当前TLAB,重新申请TLAB空间再次进行内存分配。

虚拟机定义了一个refill_waste的值,这个值可以翻译为“最大浪费空间”:当请求分配的内存大于refill_waste的时候,会选择在堆内存中分配。若小于refill_waste值,则会废弃当前TLAB,重新创建TLAB进行对象内存分配。

参考:

1. https://mp.weixin.qq.com/s/-tfs9nkufS6Hh4tSYkkCxQ

2. https://www.bilibili.com/read/cv10375688/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值