ArrayList对象在内存中占用24个字节,并且在栈上分配。
##java内存分布jol查看工具的查询结果
java.util.ArrayList object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000005 (biasable; age: 0)
8 4 (object header: class) 0x00032490
12 4 int AbstractList.modCount 0
16 4 int ArrayList.size 0
20 4 java.lang.Object[] ArrayList.elementData
##实验代码
import java.util.ArrayList;
import java.util.List;
public class OutOfMemoryTest {
public static void main(String[] args) {
List<MiBigObject> miBigObjects = new ArrayList<>(260000);
System.out.println(miBigObjects);
}
}
ThreadLocalAllocBuffer::allocate
方法确实负责从线程本地分配缓冲区(TLAB)中分配内存。这个方法尝试在当前线程的 TLAB 中分配指定大小的内存块。
分析代码
-
获取当前顶部指针:
HeapWord* obj = top();
获取当前 TLAB 的顶部指针。
-
检查空间是否足够:
if (pointer_delta(end(), obj) >= size)
检查从当前顶部指针到 TLAB 结束的剩余空间是否足够容纳请求的大小。
-
分配内存:
- 如果空间足够,方法将顶部指针
top
向前移动size
个HeapWord
,并返回原来的顶部指针obj
作为分配的内存块的起始地址。
- 如果空间足够,方法将顶部指针
-
断言检查:
- 在
ASSERT
宏定义的情况下,代码会将分配的内存块(除了对象头部)填充为一个特殊的值badHeapWordVal
,以确保并发 GC 线程不会错误地解析这块内存。
- 在
-
更新顶部指针:
set_top(obj + size);
更新 TLAB 的顶部指针。
-
返回分配的内存:
- 如果分配成功,返回
obj
;如果失败,返回NULL
。
- 如果分配成功,返回
计算分配的字节数
size
参数表示要分配的HeapWord
数量。- 每个
HeapWord
的大小通常为 8 字节(在 64 位系统中)。
因此,如果 size = 3
,则分配的内存大小为: 3 HeapWords×8 bytes/HeapWord=24 bytes3 HeapWords×8 bytes/HeapWord=24 bytes
总结
代码展示了如何从线程本地分配缓冲区中分配内存。在这个例子中,请求分配的大小为 3 个 HeapWord
,即 24 字节。这种分配方式是为了减少分配时的锁争用,提高内存分配效率。
这段代码是在 TLAB 上分配了 24 字节的内存。这种分配是在 Java 堆上进行的,而不是在栈上。TLAB 是 Java 堆的一部分,用于提高对象分配的效率。
##C++源码
HeapWord* MemAllocator::mem_allocate(Allocation& allocation) const {
if (UseTLAB) {
HeapWord* result = allocate_inside_tlab(allocation);
if (result != NULL) {
return result;
}
}
return allocate_outside_tlab(allocation);
}
HeapWord* MemAllocator::allocate_inside_tlab(Allocation& allocation) const {
assert(UseTLAB, "should use UseTLAB");
// Try allocating from an existing TLAB.
HeapWord* mem = _thread->tlab().allocate(_word_size);
if (mem != NULL) {
return mem;
}
// Try refilling the TLAB and allocating the object in it.
return allocate_inside_tlab_slow(allocation);
}
inline HeapWord* ThreadLocalAllocBuffer::allocate(size_t size) {
invariants();
HeapWord* obj = top();
if (pointer_delta(end(), obj) >= size) {
// successful thread-local allocation
#ifdef ASSERT
// Skip mangling the space corresponding to the object header to
// ensure that the returned space is not considered parsable by
// any concurrent GC thread.
size_t hdr_size = oopDesc::header_size();
Copy::fill_to_words(obj + hdr_size, size - hdr_size, badHeapWordVal);
#endif // ASSERT
// This addition is safe because we know that top is
// at least size below end, so the add can't wrap.
set_top(obj + size);
invariants();
return obj;
}
return NULL;
}
##gdb调试堆栈 3个 word 。一个word=8个字节。3*8=24字节。
#0 ThreadLocalAllocBuffer::allocate (this=0x7ffff0028a30, size=3) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/gc/shared/threadLocalAllocBuffer.inline.hpp:40
#1 0x00007ffff677a0a4 in MemAllocator::allocate_inside_tlab (this=0x7ffff7bfce30, allocation=...)
at /home/yym/openjdk17/jdk17-master/src/hotspot/share/gc/shared/memAllocator.cpp:274
#2 0x00007ffff677a3bf in MemAllocator::mem_allocate (this=0x7ffff7bfce30, allocation=...) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/gc/shared/memAllocator.cpp:352
#3 0x00007ffff677a428 in MemAllocator::allocate (this=0x7ffff7bfce30) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/gc/shared/memAllocator.cpp:365
#4 0x00007ffff6351347 in CollectedHeap::obj_allocate (this=0x7ffff00453d0, klass=0x100054468, size=3, __the_thread__=0x7ffff0028920)
at /home/yym/openjdk17/jdk17-master/src/hotspot/share/gc/shared/collectedHeap.inline.hpp:36
#5 0x00007ffff6344ef4 in InstanceKlass::allocate_instance (this=0x100054468, __the_thread__=0x7ffff0028920)
at /home/yym/openjdk17/jdk17-master/src/hotspot/share/oops/instanceKlass.cpp:1385
#6 0x00007ffff63687d9 in InterpreterRuntime::_new (current=0x7ffff0028920, pool=0x7fffd9b70330, index=35)
at /home/yym/openjdk17/jdk17-master/src/hotspot/share/interpreter/interpreterRuntime.cpp:243
#7 0x00007fffe1023ad2 in ?? ()
#8 0x00007fffe1023a46 in ?? ()
#9 0x00000000fff37f50 in ?? ()
#10 0x00007ffff7bfcfb0 in ?? ()
#11 0x00007fffd9b73d4d in ?? ()
#12 0x00007ffff7bfd038 in ?? ()
#13 0x00007fffd9b7af60 in ?? ()
#14 0x0000000000000000 in ?? ()