Skip to main content

java 对象大小

· 15 min read

背景

排查一个gc问题的时候想到需要了解java的对象大小

举例这样创建一个1099 的对象会占用多少个字节呢?

那如果是一个特定的对象NumClass

public class NumClass{
public int num1 ;
public int num2 ;
}

那样创建NunClass[] 又占用多少字节呢?

## 这样 的array占用多少字节呢? 
Object[] array = new Object[10245] ;
## 这样 的array占用多少字节呢?
Object[] array = new NumClass[10245] ;

结论是两者占用的字节是一样的

object 数组例子

先上最简单的new Object的代码,在这个例子里面: 创建了一个长度是10245的对象数组

package com;
public class Hello{
public static volatile Object[] arr ;
public static void main(String [] argv){
arr = new Object[10245]; // 创建一个对象数组 , 数组也是一个对象 , 那么这个对象有多大呢?
arr[1] = "hihi";

}
}

实际上是在64位机器上,没有开启指针压缩的情况下是: 8+ 4 + 10245*8个字节长度

oop 是指针oopDesc* 的别名

typedef class oopDesc*                    oop;
typedef class instanceOopDesc* instanceOop;
typedef class arrayOopDesc* arrayOop;
typedef class objArrayOopDesc* objArrayOop;
typedef class typeArrayOopDesc* typeArrayOop;
+-----------++----------++-------++------+           
| || || || |
| || || || |
| MarkWord || length || oop || oop |
+-----------++----------++-------++------+ repeat 10254 次

jol

核心函数:

jol\jol-core\src\main\java\org\openjdk\jol\layouters\CurrentLayouter.java

@Override
public ClassLayout layout(ClassData data) {
VirtualMachine vm = VM.current();

if (data.isArray()) {
// special case of arrays
int base = vm.arrayBaseOffset(data.arrayComponentType());
int scale = vm.arrayIndexScale(data.arrayComponentType());

long instanceSize = MathUtil.align(base + data.arrayLength() * scale, vm.objectAlignment());

SortedSet<FieldLayout> result = new TreeSet<>();
result.add(new FieldLayout(FieldData.create(data.arrayClass(), "<elements>", data.arrayComponentType()), base, scale * data.arrayLength()));
return ClassLayout.create(data, result, CURRENT, instanceSize, false);
}

Collection<FieldData> fields = data.fields();

SortedSet<FieldLayout> result = new TreeSet<>();
for (FieldData f : fields) {
result.add(new FieldLayout(f, vm.fieldOffset(f.refField()), vm.sizeOfField(f.typeClass())));
}

long instanceSize;
if (result.isEmpty()) {
instanceSize = vm.objectHeaderSize();
} else {
FieldLayout f = result.last();
instanceSize = f.offset() + f.size();
// TODO: This calculation is incorrect if there is a trailing @Contended field, or the instance is @Contended
}
instanceSize = MathUtil.align(instanceSize, vm.objectAlignment());
return ClassLayout.create(data, result, CURRENT, instanceSize, true);
}
  static int length_offset_in_bytes() {
return UseCompressedClassPointers ? klass_gap_offset_in_bytes() :
sizeof(arrayOopDesc);
}

创建一个数组

(gdb) bt
#0 arrayOopDesc::length_offset_in_bytes () at /var/jdk/src/hotspot/share/oops/arrayOop.hpp:83
#1 0x00007f93c2fdc06e in arrayOopDesc::length_addr_impl (obj_ptr=0x7162010c0) at /var/jdk/src/hotspot/share/oops/arrayOop.hpp:67
#2 0x00007f93c2fdc0ba in arrayOopDesc::length (this=0x7162010c0) at /var/jdk/src/hotspot/share/oops/arrayOop.hpp:114
#3 0x00007f93c3239521 in arrayOopDesc::is_within_bounds (this=0x7162010c0, index=10) at /var/jdk/src/hotspot/share/oops/arrayOop.hpp:110
#4 0x00007f93c3239690 in typeArrayOopDesc::byte_at_addr (this=0x7162010c0, which=10) at /var/jdk/src/hotspot/share/oops/typeArrayOop.inline.hpp:48
#5 0x00007f93c323972d in typeArrayOopDesc::byte_at_put (this=0x7162010c0, which=10, contents=112 'p') at /var/jdk/src/hotspot/share/oops/typeArrayOop.inline.hpp:96
#6 0x00007f93c389e259 in java_lang_String::create_from_unicode (unicode=0x7f93bc037c88, length=33, __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/javaClasses.cpp:300
#7 0x00007f93c3f7b91d in StringTable::do_intern (string_or_null_h=..., name=0x7f93bc037c88, len=33, hash=2694772907, __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/stringTable.cpp:347
#8 0x00007f93c3f7b87e in StringTable::intern (string_or_null_h=..., name=0x7f93bc037c88, len=33, __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/stringTable.cpp:336
#9 0x00007f93c3f7b5b0 in StringTable::intern (symbol=0x7f93c0018d38, __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/stringTable.cpp:296
#10 0x00007f93c35740b5 in ConstantPool::uncached_string_at (this=0x7f938c02e0a0, which=250, __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/oops/constantPool.cpp:1171
#11 0x00007f93c36a19cd in fieldDescriptor::string_initial_value (this=0x7f93c2bd3a68, __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/runtime/fieldDescriptor.cpp:103
#12 0x00007f93c389ff2d in initialize_static_string_field (fd=0x7f93c2bd3a68, mirror=..., __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/javaClasses.cpp:809
#13 0x00007f93c38a0444 in initialize_static_field (fd=0x7f93c2bd3a68, mirror=..., __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/javaClasses.cpp:866
#14 0x00007f93c3869f51 in InstanceKlass::do_local_static_fields (this=0x8000431a0, f=0x7f93c38a0365 <initialize_static_field(fieldDescriptor*, Handle, JavaThread*)>, mirror=..., __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/oops/instanceKlass.cpp:1672
#15 0x00007f93c38a08d5 in java_lang_Class::initialize_mirror_fields (k=0x8000431a0, mirror=..., protection_domain=..., classData=..., __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/javaClasses.cpp:930
#16 0x00007f93c38a10d1 in java_lang_Class::create_mirror (k=0x8000431a0, class_loader=..., module=..., protection_domain=..., classData=..., __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/javaClasses.cpp:1035
#17 0x00007f93c34c6144 in ClassFileParser::fill_instance_klass (this=0x7f93c2bd3dd0, ik=0x8000431a0, changed_by_loadhook=false, cl_inst_info=..., __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/classFileParser.cpp:5426
#18 0x00007f93c34c532e in ClassFileParser::create_instance_klass (this=0x7f93c2bd3dd0, changed_by_loadhook=false, cl_inst_info=..., __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/classFileParser.cpp:5255
#19 0x00007f93c3b554d1 in KlassFactory::create_from_stream (stream=0x7f93bc036fb0, name=0x7f93c00001f8, loader_data=0x7f93bc121170, cl_info=..., __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/klassFactory.cpp:202
#20 0x00007f93c34d86e9 in ClassLoader::load_class (name=0x7f93c00001f8, search_append_only=false, __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/classLoader.cpp:1231
#21 0x00007f93c4000806 in SystemDictionary::load_instance_class_impl (class_name=0x7f93c00001f8, class_loader=..., __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/systemDictionary.cpp:1289
#22 0x00007f93c4000ba3 in SystemDictionary::load_instance_class (name_hash=2036240099, name=0x7f93c00001f8, class_loader=..., __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/systemDictionary.cpp:1354
#23 0x00007f93c3ffeca9 in SystemDictionary::resolve_instance_class_or_null (name=0x7f93c00001f8, class_loader=..., protection_domain=..., __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/systemDictionary.cpp:723
#24 0x00007f93c3ffd82e in SystemDictionary::resolve_instance_class_or_null_helper (class_name=0x7f93c00001f8, class_loader=..., protection_domain=..., __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/systemDictionary.cpp:294
#25 0x00007f93c3ffd6d4 in SystemDictionary::resolve_or_null (class_name=0x7f93c00001f8, class_loader=..., protection_domain=..., __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/systemDictionary.cpp:277
#26 0x00007f93c3ffd617 in SystemDictionary::resolve_or_fail (class_name=0x7f93c00001f8, class_loader=..., protection_domain=..., throw_error=true, __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/systemDictionary.cpp:263
#27 0x00007f93c32b8d98 in SystemDictionary::resolve_or_fail (class_name=0x7f93c00001f8, throw_error=true, __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/systemDictionary.hpp:100
#28 0x00007f93c40dca98 in vmClasses::resolve (id=vmClassID::Throwable_klass_knum, __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/vmClasses.cpp:99
#29 0x00007f93c40dcb96 in vmClasses::resolve_until (limit_id=vmClassID::SoftReference_klass_knum, start_id=@0x7f93c2bd48f0: vmClassID::Cloneable_klass_knum, __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/vmClasses.cpp:108
#30 0x00007f93c40dd59a in vmClasses::resolve_through (last_id=vmClassID::Reference_klass_knum, start_id=@0x7f93c2bd48f0: vmClassID::Cloneable_klass_knum, __the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/vmClasses.hpp:64
#31 0x00007f93c40dce23 in vmClasses::resolve_all (__the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/vmClasses.cpp:168
#32 0x00007f93c4001ab2 in SystemDictionary::initialize (__the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/classfile/systemDictionary.cpp:1655
#33 0x00007f93c40812fb in Universe::genesis (__the_thread__=0x7f93bc028fa0) at /var/jdk/src/hotspot/share/memory/universe.cpp:335
#34 0x00007f93c408378f in universe2_init () at /var/jdk/src/hotspot/share/memory/universe.cpp:937
#35 0x00007f93c3863d8a in init_globals () at /var/jdk/src/hotspot/share/runtime/init.cpp:132
#36 0x00007f93c404a1ca in Threads::create_vm (args=0x7f93c2bd4d50, canTryAgain=0x7f93c2bd4c5b) at /var/jdk/src/hotspot/share/runtime/thread.cpp:2843
#37 0x00007f93c396f43b in JNI_CreateJavaVM_inner (vm=0x7f93c2bd4da8, penv=0x7f93c2bd4db0, args=0x7f93c2bd4d50) at /var/jdk/src/hotspot/share/prims/jni.cpp:3613
#38 0x00007f93c396f787 in JNI_CreateJavaVM (vm=0x7f93c2bd4da8, penv=0x7f93c2bd4db0, args=0x7f93c2bd4d50) at /var/jdk/src/hotspot/share/prims/jni.cpp:3701
#39 0x00007f93c50e6a6a in InitializeJVM (pvm=0x7f93c2bd4da8, penv=0x7f93c2bd4db0, ifn=0x7f93c2bd4e00) at /var/jdk/src/java.base/share/native/libjli/java.c:1459
#40 0x00007f93c50e35ec in JavaMain (_args=0x7ffedd44e1a0) at /var/jdk/src/java.base/share/native/libjli/java.c:411
#41 0x00007f93c50ea5ec in ThreadJavaMain (args=0x7ffedd44e1a0) at /var/jdk/src/java.base/unix/native/libjli/java_md.c:651
#42 0x00007f93c4f45b43 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#43 0x00007f93c4fd6bb4 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:100

分配数组大小:

  static int array_size(int length) {
const uint OopsPerHeapWord = HeapWordSize/heapOopSize;
assert(OopsPerHeapWord >= 1 && (HeapWordSize % heapOopSize == 0),
"Else the following (new) computation would be in error");
uint res = ((uint)length + OopsPerHeapWord - 1)/OopsPerHeapWord;
#ifdef ASSERT
// The old code is left in for sanity-checking; it'll
// go away pretty soon. XXX
// Without UseCompressedOops, this is simply:
// oop->length() * HeapWordsPerOop;
// With narrowOops, HeapWordsPerOop is 1/2 or equal 0 as an integer.
// The oop elements are aligned up to wordSize
const uint HeapWordsPerOop = heapOopSize/HeapWordSize;
uint old_res;
if (HeapWordsPerOop > 0) {
old_res = length * HeapWordsPerOop;
} else {
old_res = align_up((uint)length, OopsPerHeapWord)/OopsPerHeapWord;
}
assert(res == old_res, "Inconsistency between old and new.");
#endif // ASSERT
return res;
}
Thread 2 "java" hit Breakpoint 5, jni_invoke_static (env=0x7fca48029310, result=0x7fca4c534bf0, receiver=0x0, call_type=JNI_STATIC, method_id=0x7fca48542d50, args=0x7fca4c534c60, __the_thread__=0x7fca48029030) at /var/jdk/src/hotspot/share/prims/jni.cpp:881
881 args->push_arguments_on(&java_args);
(gdb) p method._value->print()
{method}
- this oop: 0x00007fca14411240
- method holder: 'com/Hello'
- constants: 0x00007fca14411020 constant pool [20] {0x00007fca14411020} for 'com/Hello' cache=0x00007fca14411348
- access: 0x9 public static
- name: 'main'
- signature: '([Ljava/lang/String;)V'
- max stack: 2
- max locals: 1
- size of params: 1
- method size: 13
- vtable index: -2
- i2i entry: 0x00007fca3900dc00
- adapters: AHE@0x00007fca4812b8d0: 0xb i2c: 0x00007fca39114d60 c2i: 0x00007fca39114e1a c2iUV: 0x00007fca39114de4 c2iNCI: 0x00007fca39114e57
- compiled entry 0x00007fca39114e1a
- code size: 10
- code start: 0x00007fca14411230
- code end (excl): 0x00007fca1441123a
- checked ex length: 0
- linenumber start: 0x00007fca1441123a
- localvar length: 0
$17 = void
(gdb) bt
#0 jni_invoke_static (env=0x7fca48029310, result=0x7fca4c534bf0, receiver=0x0, call_type=JNI_STATIC, method_id=0x7fca48542d50, args=0x7fca4c534c60, __the_thread__=0x7fca48029030) at /var/jdk/src/hotspot/share/prims/jni.cpp:881
#1 0x00007fca4d2c141c in jni_CallStaticVoidMethod (env=0x7fca48029310, cls=0x7fca4802b368, methodID=0x7fca48542d50) at /var/jdk/src/hotspot/share/prims/jni.cpp:1710
#2 0x00007fca4ea4415e in JavaMain (_args=0x7fff1ad56b60) at /var/jdk/src/java.base/share/native/libjli/java.c:545
#3 0x00007fca4ea4a5ec in ThreadJavaMain (args=0x7fff1ad56b60) at /var/jdk/src/java.base/unix/native/libjli/java_md.c:651
#4 0x00007fca4e8a5b43 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#5 0x00007fca4e936bb4 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:100
Thread 2 "java" hit Breakpoint 5, jni_invoke_static (env=0x7f8674029310, result=0x7f86791b0bf0, receiver=0x0, call_type=JNI_STATIC, method_id=0x7f8674652560, args=0x7f86791b0c60, __the_thread__=0x7f8674029030) at /var/jdk/src/hotspot/share/prims/jni.cpp:881
881 args->push_arguments_on(&java_args);
(gdb) p method._value->print()
{method}
- this oop: 0x00007f8644411240
- method holder: 'com/Hello'
- constants: 0x00007f8644411020 constant pool [20] {0x00007f8644411020} for 'com/Hello' cache=0x00007f8644411348
- access: 0x9 public static
- name: 'main'
- signature: '([Ljava/lang/String;)V'
- max stack: 2
- max locals: 1
- size of params: 1
- method size: 13
- vtable index: -2
- i2i entry: 0x00007f866500dc00
- adapters: AHE@0x00007f867412b8d0: 0xb i2c: 0x00007f8665114d60 c2i: 0x00007f8665114e1a c2iUV: 0x00007f8665114de4 c2iNCI: 0x00007f8665114e57
- compiled entry 0x00007f8665114e1a
- code size: 10
- code start: 0x00007f8644411230
- code end (excl): 0x00007f864441123a
- checked ex length: 0
- linenumber start: 0x00007f864441123a
- localvar length: 0
$23 = void
(gdb) enable 1
(gdb) c
Continuing.

Thread 2 "java" hit Breakpoint 1, oopFactory::new_objArray (klass=0x800040f80, length=2019, __the_thread__=0x7f8674029030) at /var/jdk/src/hotspot/share/memory/oopFactory.cpp:118
118 assert(klass->is_klass(), "must be instance class");
(gdb) bt
#0 oopFactory::new_objArray (klass=0x800040f80, length=2019, __the_thread__=0x7f8674029030) at /var/jdk/src/hotspot/share/memory/oopFactory.cpp:118
#1 0x00007f8679e68a5b in InterpreterRuntime::anewarray (current=0x7f8674029030, pool=0x7f8644411020, index=2, size=2019) at /var/jdk/src/hotspot/share/interpreter/interpreterRuntime.cpp:254
#2 0x00007f8665024083 in ?? ()
#3 0x00007f867b4520a0 in TemplateInterpreter::_active_table () from /var/jdk/build/linux-x86_64-server-slowdebug/jdk/lib/server/libjvm.so
#4 0x00007f8665024002 in ?? ()
#5 0x00007f86791b07b0 in ?? ()
#6 0x00007f8644411233 in ?? ()
#7 0x00007f86791b0808 in ?? ()
#8 0x00007f8644411348 in ?? ()
#9 0x0000000000000000 in ?? ()
Bottom (innermost) frame selected; you cannot go down.
(gdb) p _do_zero
$35 = true
(gdb) n
413 if (_do_zero) {
(gdb) n
414 mem_clear(mem);
(gdb) n
416 arrayOopDesc::set_length(mem, _length);
(gdb) l
411 // concurrent GC.
412 assert(_length >= 0, "length should be non-negative");
413 if (_do_zero) {
414 mem_clear(mem);
415 }
416 arrayOopDesc::set_length(mem, _length);
417 return finish(mem);
418 }
419
420 oop ClassAllocator::initialize(HeapWord* mem) const {
(gdb) up
#1 0x00007f867a27af4b in MemAllocator::allocate (this=0x7f86791b0650) at /var/jdk/src/hotspot/share/gc/shared/memAllocator.cpp:365
365 obj = initialize(mem);
(gdb) down
#0 ObjArrayAllocator::initialize (this=0x7f86791b0650, mem=0x715e73dd0) at /var/jdk/src/hotspot/share/gc/shared/memAllocator.cpp:416
416 arrayOopDesc::set_length(mem, _length);
(gdb) s
arrayOopDesc::set_length (mem=0x715e73dd0, length=2019) at /var/jdk/src/hotspot/share/oops/arrayOop.hpp:122
122 *length_addr_impl(mem) = length;
(gdb) s
arrayOopDesc::length_addr_impl (obj_ptr=0x715e73dd0) at /var/jdk/src/hotspot/share/oops/arrayOop.hpp:66
66 char* ptr = static_cast<char*>(obj_ptr);
(gdb) l
61 return (int)hs;
62 }
63
64 // Returns the address of the length "field". See length_offset_in_bytes().
65 static int* length_addr_impl(void* obj_ptr) {
66 char* ptr = static_cast<char*>(obj_ptr);
67 return reinterpret_cast<int*>(ptr + length_offset_in_bytes());
68 }
69
70 // Check whether an element of a typeArrayOop with the given type must be
(gdb) n
67 return reinterpret_cast<int*>(ptr + length_offset_in_bytes());
(gdb) s
arrayOopDesc::length_offset_in_bytes () at /var/jdk/src/hotspot/share/oops/arrayOop.hpp:83
83 sizeof(arrayOopDesc);
(gdb) l
78 // The _length field is not declared in C++. It is allocated after the
79 // declared nonstatic fields in arrayOopDesc if not compressed, otherwise
80 // it occupies the second half of the _klass field in oopDesc.
81 static int length_offset_in_bytes() {
82 return UseCompressedClassPointers ? klass_gap_offset_in_bytes() :
83 sizeof(arrayOopDesc);
84 }
85
86 // Returns the offset of the first element.
87 static int base_offset_in_bytes(BasicType type) {
(gdb) p Use
Display all 161 possibilities? (y or n)
(gdb) p UseCompressedClassPointers
$36 = true
(gdb) s
82 return UseCompressedClassPointers ? klass_gap_offset_in_bytes() :
(gdb) s
oopDesc::klass_gap_offset_in_bytes () at /var/jdk/src/hotspot/share/oops/oop.hpp:307
307 assert(has_klass_gap(), "only applicable to compressed klass pointers");
(gdb) l
302
303 // for code generation
304 static int mark_offset_in_bytes() { return offset_of(oopDesc, _mark); }
305 static int klass_offset_in_bytes() { return offset_of(oopDesc, _metadata._klass); }
306 static int klass_gap_offset_in_bytes() {
307 assert(has_klass_gap(), "only applicable to compressed klass pointers");
308 return klass_offset_in_bytes() + sizeof(narrowKlass);
309 }
310
311 // for error reporting
(gdb) n
oopDesc::klass_gap_offset_in_bytes () at /var/jdk/src/hotspot/share/oops/oop.hpp:308
308 return klass_offset_in_bytes() + sizeof(narrowKlass);
(gdb) n
309 }
(gdb) n
arrayOopDesc::length_offset_in_bytes () at /var/jdk/src/hotspot/share/oops/arrayOop.hpp:83
83 sizeof(arrayOopDesc);
(gdb) n
84 }
(gdb) n
arrayOopDesc::length_addr_impl (obj_ptr=0x715e73dd0) at /var/jdk/src/hotspot/share/oops/arrayOop.hpp:68
68 }
(gdb) n
arrayOopDesc::set_length (mem=0x715e73dd0, length=2019) at /var/jdk/src/hotspot/share/oops/arrayOop.hpp:122
122 *length_addr_impl(mem) = length;
(gdb) n
123 }
(gdb) p (int *)mem@20
Only values in memory can be extended with '@'.
(gdb) p *(int *)mem@20
$37 = {-1163019586, -1163019586, -1163019586, 2019, 0 <repeats 16 times>}

byte code 生成入口

// jdk/src/hotspot/share/interpreter/templateInterpreter.cpp
void DispatchTable::set_entry(int i, EntryPoint& entry) {
assert(0 <= i && i < length, "index out of bounds");
assert(number_of_states == 10, "check the code below");
_table[btos][i] = entry.entry(btos);
_table[ztos][i] = entry.entry(ztos);
_table[ctos][i] = entry.entry(ctos);
_table[stos][i] = entry.entry(stos);
_table[atos][i] = entry.entry(atos);
_table[itos][i] = entry.entry(itos);
_table[ltos][i] = entry.entry(ltos);
_table[ftos][i] = entry.entry(ftos);
_table[dtos][i] = entry.entry(dtos);
_table[vtos][i] = entry.entry(vtos);
}
//src/hotspot/share/interpreter/bytecodes.hpp
_new = 187, // 0xbb
_newarray = 188, // 0xbc
_anewarray = 189, // 0xbd
_arraylength = 190, // 0xbe

堆栈:

Thread 2 "java" hit Breakpoint 13, 0x00007fffe1011b13 in ?? ()
(gdb) x/20i $pc
=> 0x7fffe1011b13: movzwl 0x1(%r13),%eax
0x7fffe1011b18: bswap %eax
0x7fffe1011b1a: sar $0x10,%eax
0x7fffe1011b1d: movzbl 0x3(%r13),%ebx
0x7fffe1011b22: add $0x3,%r13
0x7fffe1011b26: movabs $0x7ffff7bca0a0,%r10
0x7fffe1011b30: jmp *(%r10,%rbx,8)
0x7fffe1011b34: nop
0x7fffe1011b35: nop
0x7fffe1011b36: nop
0x7fffe1011b37: nop
0x7fffe1011b38: int3
0x7fffe1011b39: int3
0x7fffe1011b3a: int3
0x7fffe1011b3b: int3
0x7fffe1011b3c: int3
0x7fffe1011b3d: int3
0x7fffe1011b3e: int3
0x7fffe1011b3f: int3
0x7fffe1011b40: and %al,(%rax,%rax,1)

0x00007fffe1011b1d in ?? ()
(gdb) info registers
rax 0x2805 10245
rbx 0x11 17
rcx 0x2 2
rdx 0x8 8
rsi 0x555555581230 93824992416304
rdi 0x7ffff0028f70 140737220087664
rbp 0x7ffff59fe7f8 0x7ffff59fe7f8
rsp 0x7ffff59fe7b0 0x7ffff59fe7b0
r8 0x8 8
r9 0x0 0
r10 0x7ffff7bcc8a0 140737349732512
r11 0x216 534
r12 0x0 0
r13 0x7fffb4411230 140736217551408
r14 0x7ffff59fe808 140737314285576
r15 0x7ffff0028f70 140737220087664
rip 0x7fffe1011b1d 0x7fffe1011b1d
eflags 0x216 [ PF AF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0

anewarray 汇编代码:

(gdb) x/20i $pc
=> 0x7fffe102400a: lea 0x8(%rsp),%rax
0x7fffe102400f: mov %r13,-0x40(%rbp)
0x7fffe1024013: cmpq $0x0,-0x10(%rbp)
0x7fffe102401b: je 0x7fffe1024035
0x7fffe1024021: movabs $0x7ffff71becc8,%rdi
0x7fffe102402b: and $0xfffffffffffffff0,%rsp
0x7fffe102402f: call 0x7ffff694f3c0 <_ZN14MacroAssembler7debug64EPclPl>
0x7fffe1024034: hlt
0x7fffe1024035: push %r10
0x7fffe1024037: cmp 0x16ae2ec2(%rip),%r12 # 0x7ffff7b06f00 <_ZN14CompressedOops11_narrow_oopE>
0x7fffe102403e: je 0x7fffe1024058
0x7fffe1024044: movabs $0x7ffff7311c28,%rdi
0x7fffe102404e: and $0xfffffffffffffff0,%rsp
0x7fffe1024052: call 0x7ffff694f3c0 <_ZN14MacroAssembler7debug64EPclPl>
0x7fffe1024057: hlt
0x7fffe1024058: pop %r10
0x7fffe102405a: mov %r15,%rdi
0x7fffe102405d: vzeroupper
0x7fffe1024060: mov %rbp,0x2d0(%r15)
0x7fffe1024067: mov %rax,0x2c0(%r15)
(gdb) x/200i $pc
=> 0x7fffe102400a: lea 0x8(%rsp),%rax
0x7fffe102400f: mov %r13,-0x40(%rbp)
0x7fffe1024013: cmpq $0x0,-0x10(%rbp)
0x7fffe102401b: je 0x7fffe1024035
0x7fffe1024021: movabs $0x7ffff71becc8,%rdi
0x7fffe102402b: and $0xfffffffffffffff0,%rsp
0x7fffe102402f: call 0x7ffff694f3c0 <_ZN14MacroAssembler7debug64EPclPl>
0x7fffe1024034: hlt
0x7fffe1024035: push %r10
0x7fffe1024037: cmp 0x16ae2ec2(%rip),%r12 # 0x7ffff7b06f00 <_ZN14CompressedOops11_narrow_oopE>
0x7fffe102403e: je 0x7fffe1024058
0x7fffe1024044: movabs $0x7ffff7311c28,%rdi
0x7fffe102404e: and $0xfffffffffffffff0,%rsp
0x7fffe1024052: call 0x7ffff694f3c0 <_ZN14MacroAssembler7debug64EPclPl>
0x7fffe1024057: hlt
0x7fffe1024058: pop %r10
0x7fffe102405a: mov %r15,%rdi
0x7fffe102405d: vzeroupper
0x7fffe1024060: mov %rbp,0x2d0(%r15)
0x7fffe1024067: mov %rax,0x2c0(%r15)
0x7fffe102406e: test $0xf,%esp
0x7fffe1024074: je 0x7fffe102408c
0x7fffe102407a: sub $0x8,%rsp
0x7fffe102407e: call 0x7ffff65cf968 <_ZN18InterpreterRuntime9anewarrayEP10JavaThreadP12ConstantPoolii>
0x7fffe1024083: add $0x8,%rsp
0x7fffe1024087: jmp 0x7fffe1024091
0x7fffe102408c: call 0x7ffff65cf968 <_ZN18InterpreterRuntime9anewarrayEP10JavaThreadP12ConstantPoolii>
0x7fffe1024091: push %rax
0x7fffe1024092: push %rdi
0x7fffe1024093: push %rsi
0x7fffe1024094: push %rdx
--Type <RET> for more, q to quit, c to continue without paging--
0x7fffe1024095: push %rcx
0x7fffe1024096: push %r8
0x7fffe1024098: push %r9
0x7fffe102409a: push %r10
0x7fffe102409c: push %r11
0x7fffe102409e: test $0xf,%esp
0x7fffe10240a4: je 0x7fffe10240bc
0x7fffe10240aa: sub $0x8,%rsp
0x7fffe10240ae: call 0x7ffff5d1c04e <_ZN6Thread7currentEv>
0x7fffe10240b3: add $0x8,%rsp
0x7fffe10240b7: jmp 0x7fffe10240c1
0x7fffe10240bc: call 0x7ffff5d1c04e <_ZN6Thread7currentEv>
0x7fffe10240c1: pop %r11
0x7fffe10240c3: pop %r10
0x7fffe10240c5: pop %r9
0x7fffe10240c7: pop %r8
0x7fffe10240c9: pop %rcx
0x7fffe10240ca: pop %rdx
0x7fffe10240cb: pop %rsi
0x7fffe10240cc: pop %rdi
0x7fffe10240cd: cmp %rax,%r15
0x7fffe10240d0: je 0x7fffe10240ea
0x7fffe10240d6: movabs $0x7ffff7311da0,%rdi
0x7fffe10240e0: and $0xfffffffffffffff0,%rsp
0x7fffe10240e4: call 0x7ffff694f3c0 <_ZN14MacroAssembler7debug64EPclPl>
0x7fffe10240e9: hlt
0x7fffe10240ea: pop %rax
0x7fffe10240eb: movq $0x0,0x2c0(%r15)
0x7fffe10240f6: movq $0x0,0x2d0(%r15)
0x7fffe1024101: movq $0x0,0x2c8(%r15)
0x7fffe102410c: vzeroupper
--Type <RET> for more, q to quit, c to continue without paging--
0x7fffe102410f: cmpq $0x0,0x8(%r15)
0x7fffe1024117: je 0x7fffe1024122
0x7fffe102411d: jmp 0x7fffe1000c20
0x7fffe1024122: mov 0x318(%r15),%rax
0x7fffe1024129: movq $0x0,0x318(%r15)
0x7fffe1024134: mov -0x40(%rbp),%r13
0x7fffe1024138: mov -0x38(%rbp),%r14
0x7fffe102413c: ret
0x7fffe102413d: movzbl 0x3(%r13),%ebx
0x7fffe1024142: add $0x3,%r13
0x7fffe1024146: movabs $0x7ffff7bcc0a0,%r10
0x7fffe1024150: jmp *(%r10,%rbx,8)
0x7fffe1024154: nop
0x7fffe1024155: nop


内存分配

用的是jdk11以上版本,我这个jdk是用g1来做gc的,所以看看g1 是怎么分配的

(gdb) bt
#0 HeapRegion::par_allocate_impl (this=0x7ffff00e11b0, min_word_size=256, desired_word_size=63020, actual_size=0x7ffff59fcba8)
at /home/dai/jdk/src/hotspot/share/gc/g1/heapRegion.inline.hpp:63
#1 0x00007ffff640bdcc in HeapRegion::par_allocate (this=0x7ffff00e11b0, min_word_size=256, desired_word_size=63020, actual_word_size=0x7ffff59fcba8)
at /home/dai/jdk/src/hotspot/share/gc/g1/heapRegion.inline.hpp:225
#2 0x00007ffff640bfcb in G1AllocRegion::par_allocate (this=0x7ffff0052e10, alloc_region=0x7ffff00e11b0, min_word_size=256, desired_word_size=63020,
actual_word_size=0x7ffff59fcba8) at /home/dai/jdk/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp:63
#3 0x00007ffff640c0c6 in G1AllocRegion::attempt_allocation (this=0x7ffff0052e10, min_word_size=256, desired_word_size=63020, actual_word_size=0x7ffff59fcba8)
at /home/dai/jdk/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp:77
#4 0x00007ffff6447142 in G1Allocator::attempt_allocation (this=0x7ffff0052d50, min_word_size=256, desired_word_size=63020, actual_word_size=0x7ffff59fcba8)
at /home/dai/jdk/src/hotspot/share/gc/g1/g1Allocator.inline.hpp:62
#5 0x00007ffff6447b1d in G1CollectedHeap::attempt_allocation (this=0x7ffff0048bf0, min_word_size=256, desired_word_size=63020,
actual_word_size=0x7ffff59fcba8) at /home/dai/jdk/src/hotspot/share/gc/g1/g1CollectedHeap.cpp:709
#6 0x00007ffff64385ea in G1CollectedHeap::allocate_new_tlab (this=0x7ffff0048bf0, min_size=256, requested_size=63020, actual_size=0x7ffff59fcba8)
at /home/dai/jdk/src/hotspot/share/gc/g1/g1CollectedHeap.cpp:359
#7 0x00007ffff69e1cf6 in MemAllocator::allocate_inside_tlab_slow (this=0x7ffff59fcc00, allocation=...)
at /home/dai/jdk/src/hotspot/share/gc/shared/memAllocator.cpp:318
#8 0x00007ffff69e1bc2 in MemAllocator::allocate_inside_tlab (this=0x7ffff59fcc00, allocation=...)
at /home/dai/jdk/src/hotspot/share/gc/shared/memAllocator.cpp:278
#9 0x00007ffff69e1eb9 in MemAllocator::mem_allocate (this=0x7ffff59fcc00, allocation=...) at /home/dai/jdk/src/hotspot/share/gc/shared/memAllocator.cpp:350
#10 0x00007ffff69e1f22 in MemAllocator::allocate (this=0x7ffff59fcc00) at /home/dai/jdk/src/hotspot/share/gc/shared/memAllocator.cpp:363
#11 0x00007ffff6260d84 in CollectedHeap::array_allocate (this=0x7ffff0048bf0, klass=0x8000407c0, size=106, length=825, do_zero=true,
__the_thread__=0x7ffff0028f70) at /home/dai/jdk/src/hotspot/share/gc/shared/collectedHeap.inline.hpp:41
#12 0x00007ffff6db9bf2 in TypeArrayKlass::allocate_common (this=0x8000407c0, length=825, do_zero=true, __the_thread__=0x7ffff0028f70)
at /home/dai/jdk/src/hotspot/share/oops/typeArrayKlass.cpp:93
#13 0x00007ffff62f7428 in TypeArrayKlass::allocate (this=0x8000407c0, length=825, __the_thread__=0x7ffff0028f70)
at /home/dai/jdk/src/hotspot/share/oops/typeArrayKlass.hpp:68
#14 0x00007ffff6ab4757 in oopFactory::new_typeArray (type=T_BYTE, length=825, __the_thread__=0x7ffff0028f70)
at /home/dai/jdk/src/hotspot/share/memory/oopFactory.cpp:93
#15 0x00007ffff65cf8e5 in InterpreterRuntime::newarray (current=0x7ffff0028f70, type=T_BYTE, size=825)
at /home/dai/jdk/src/hotspot/share/interpreter/interpreterRuntime.cpp:247
#16 0x00007fffe1023eb2 in ?? ()
#17 0x00007ffff7bca0a0 in TemplateInterpreter::_active_table () from /home/dai/jdk/build/linux-x86_64-server-slowdebug/jdk/lib/server/libjvm.so
#18 0x00007fffe1023e31 in ?? ()
#19 0x000000062a47ab38 in ?? ()
#20 0x00007ffff59fcd88 in ?? ()
#21 0x00007fffb43a23e6 in ?? ()
#22 0x00007ffff59fcde8 in ?? ()
#23 0x00007fffb43a3520 in ?? ()
#24 0x0000000000000000 in ?? ()

array_copy 反查

java里面 System.arraycopy 函数就是copy 整个数组到新的数组里面,复制方式是浅拷贝. 最后调用的入口是下面的c++代码.所以可以通过这个函数就可以了解数组的内存布局

void ObjArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d,
int dst_pos, int length, TRAPS) {


...
size_t src_offset = (size_t) objArrayOopDesc::obj_at_offset<oop>(src_pos); <----------------------------- 开始地址
size_t dst_offset = (size_t) objArrayOopDesc::obj_at_offset<oop>(dst_pos); <---------------------------- 结束地址
assert(arrayOopDesc::obj_offset_to_raw<oop>(s, src_offset, NULL) ==
objArrayOop(s)->obj_at_addr<oop>(src_pos), "sanity");
assert(arrayOopDesc::obj_offset_to_raw<oop>(d, dst_offset, NULL) ==
objArrayOop(d)->obj_at_addr<oop>(dst_pos), "sanity");
do_copy(s, src_offset, d, dst_offset, length, CHECK);
}
}

所以java的对象数组的内存布局就像下面一样 , 这里的oop 是一个指针

64位下面是8字节

相关阅读