Java非阻塞内存分配

14

我在某个地方读到,Java可以在大约12条机器指令内为对象分配内存。这对我来说非常令人印象深刻。据我所知,JVM使用的一个技巧之一是提前分配内存块。这有助于最小化向操作系统发出的请求数量,而这可能是相当昂贵的。但即使CAS操作也可能在现代处理器上耗费多达150个周期。

因此,有人能解释一下Java内存分配的真正成本以及JVM使用哪些技巧加快分配速度吗?


一个典型的JVM只会使用操作系统来向堆添加额外的内存。大部分时间它都在重复利用已有的内存。 - Tom Hawtin - tackline
3个回答

24

JVM 为每个线程预先分配一片内存区域,即线程本地区域 (TLA 或 Thread Local Area)。 当一个线程需要分配内存时,它会在该区域内使用 "Bump the pointer allocation" 策略(如果“空闲指针”指向地址 10,而要分配的对象大小为 50,则我们只需将空闲指针增加到 60,并告诉线程可以使用地址 10 到 59 之间的内存来存储该对象)。


非常感谢。这正是我一直在寻找的东西,但不知道如何向谷歌提问。:) 但有趣的是...我唯一发现关于TLA的信息是在Oracle JRock JVM中(标志-XXtlaSize)。Sun JVM中是否存在此功能? - Denis Bazhenov
1
Sun公司的术语是Thread Local Allocation Buffer,TLA代表Translation Look-Aside缓冲区(怪IBM),并指的是硬件高速缓存映射。 - Tom Hawtin - tackline
1
没错,我已经找到了相关信息。谢谢。顺便说一下,我猜测翻译后的缩写应该是 TLB :) http://en.wikipedia.org/wiki/Translation_lookaside_buffer - Denis Bazhenov

3
最好的技巧是分代垃圾回收器。它保持堆不被碎片化,因此分配内存只需增加指向空闲空间的指针并返回旧值。如果内存用尽,垃圾回收会复制对象并以此创建一个新的未碎片化的堆。
由于不同线程必须在指向空闲内存的指针上进行同步,如果增加它们将预先分配块。因此,线程可以分配新的内存,而无需锁定。
所有这些都在此处更详细地解释:http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html

2
JVM没有单一的内存分配器。据我所知,Sun的JVM和IBM的内存管理不同。然而,通常JVM的操作方式是首先分配一个内存段,这个段足够小,可以存储在处理器的缓存中,从而使得对它的所有访问非常快速。
随着应用程序创建对象,对象将从该段内存中占用空间。在该段内分配对象的方法只是指针算术运算。
最初,对新生成段进行偏移地址计算时,偏移量为零。第一个分配的对象将拥有一个“地址”(实际上是一个偏移量),其值为零。当你分配对象时,内存管理器将会知道对象的大小,在该段内分配相应大小的空间(比如16字节),然后通过增加“偏移地址”,让内存分配快得惊人,只需要进行指针算术运算。
Sun在这里提供了白皮书:JavaHotSpot™虚拟机中的内存管理,而IBM曾在ibm.com/developerworks上提供过一些内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接