假设这将在真正的并行环境中发生,一个虚拟机,在同一时间内:
// Thread 1:
new Cat()
// Thread 2:
new Dog()
// Thread 3:
new Mouse()
JVM如何确保堆上内存分配的线程安全性?
堆是所有线程共享的,它有自己的内部数据。
为了简单起见,假设使用一个简单的压缩垃圾收集器实现-XX:+UseSerialGC,-XX:+UseParallelGC,并具有简单的增量指针来标记空闲空间的开始和在Eden(堆)中的一个连续空闲空间。
当为Cat、Dog和Mouse实例分配堆空间时,线程之间必须进行某种同步,否则它们很容易相互覆盖。这是否意味着每个new操作符都隐藏在一些同步块内?这样,许多“无锁”算法实际上并不完全无锁 ;)
我假设内存分配是由应用程序线程自己同步进行的,而不是由另一个专用线程进行的。
我知道TLAB,或者叫线程局部分配缓冲区。它允许线程在Eden中拥有一个单独的内存区域来进行分配,因此不需要同步。但是我不确定TLAB是否默认设置,这是一个非常难以理解的HotSpot功能。注意:不要将TLAB和ThreadLocal
变量混淆!我还假设,对于更复杂的垃圾收集器(如G1或非压缩垃圾收集器),需要维护更复杂的堆结构数据,例如CMS的空闲块列表,因此需要更多的同步。
更新:请让我澄清一下。我接受HotSpot JVM实现及具有和没有激活TLAB的变体的答案。
更新: 根据我的快速测试,在我的64位JDK 7上,串行、并行和CMS垃圾收集器默认启用TLAB,但对于G1 GC则未启用。