【发布时间】:2014-10-20 03:39:12
【问题描述】:
让我们假设这将在一个真正的并行环境中同时发生,一个虚拟机:
// Thread 1:
new Cat()
// Thread 2:
new Dog()
// Thread 3:
new Mouse()
JVM如何确保堆上内存分配的线程安全?
堆是所有线程的一个,它有自己的内部数据。
为简单起见,假设一个简单的压缩垃圾收集器实现,-XX:+UseSerialGC -XX:+UseParallelGC,用简单的增量指针来标记空闲空间的开始和伊甸园(堆)中的一个连续空闲空间。
当为 Cat、Dog 和 Mouse 实例分配堆空间时,线程之间必须存在某种同步,否则它们很容易结束向上覆盖彼此。这是否意味着每个 new 运算符都隐藏在一些同步块中?这样一来,许多“无锁”算法实际上并不是完全无锁的;)
我假设内存分配是由应用程序线程自己同步进行的,而不是由另一个专用线程进行的。
我知道TLABs 或线程本地分配缓冲区。它们允许线程在 Eden 中有一个单独的内存区域用于分配,因此不需要同步。但我不确定是否默认设置了 TLAB,它是一个非常晦涩的 HotSpot 功能。注意:不要混淆 TLAB 和 ThreadLocal 变量!
我还假设,对于更复杂的垃圾收集器(如 G1)或非压缩垃圾收集器,必须维护更复杂的堆结构数据,例如 CMS 的空闲块列表,因此需要更多的同步。
更新:请让我澄清一下。我接受 HotSpot JVM 实现和变体的答案,无论是否有活动的 TLAB。
更新: 根据my quick test,TLAB 默认设置为 ON,在我的 64 位 JDK 7 上,用于串行、并行和 CMS 垃圾收集器,但不适用于 G1 GC。
【问题讨论】:
-
就是这样。给每个线程自己的“区域”或“池”是一种方法。但是某种锁定协议通常会用于从单个池中分配的大型对象。
标签: java multithreading concurrency jvm new-operator