热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

javamarkword_java对象结构对象头Markword

概述对象实例由对象头、实例数据组成,其中对象头包括markword和类型指针,如果是数组,还包括数组长度;|类型|32位JVM|64位JV

概述

对象实例由对象头、实例数据组成,其中对象头包括markword和类型指针,如果是数组,还包括数组长度;

| 类型 | 32位JVM | 64位JVM|

| ------ ---- | ------------| --------- |

| markword | 32bit | 64bit |

| 类型指针 | 32bit |64bit ,开启指针压缩时为32bit |

| 数组长度 | 32bit |32bit |

5f4756c0d74c98362c0e6ba0bbb56148.png

header.png

d8468800a2c30386883e1301554ef3cb.png

compressed_header.png

可以看到

开启指针压缩时,markword占用8bytes,类型指针占用8bytes,共占用16bytes;

未开启指针压缩时,markword占用8bytes,类型指针占用4bytes,但由于java内存地址按照8bytes对齐,长度必须是8的倍数,因此会从12bytes补全到16bytes;

数组长度为4bytes,同样会进行对齐,补足到8bytes;

另外从上面的截图可以看到,开启指针压缩之后,对象类型指针为0xf800c005,但实际的类型指针为0x7c0060028;那么指针是如何压缩的呢?实际上由于java地址一定是8的倍数,因此将0xf800c005*8即可得到实际的指针0x7c0060028,关于指针压缩的更多知识可参考官方文档。

markword结构

markword的结构,定义在markOop.hpp文件:

32 bits:

--------

hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)

JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object)

size:32 ------------------------------------------>| (CMS free block)

PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)

64 bits:

--------

unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object)

JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object)

PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)

size:64 ----------------------------------------------------->| (CMS free block)

unused:25 hash:31 -->| cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && normal object)

JavaThread*:54 epoch:2 cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && biased object)

narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)

unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)

[ptr | 00] locked ptr points to real header on stack

[header | 0 | 01] unlocked regular object header

[ptr | 10] monitor inflated lock (header is wapped out)

[ptr | 11] marked used by markSweep to mark an object

由于目前基本都在使用64位JVM,此处不再对32位的结构进行详细说明:

偏向锁标识位锁标识位锁状态存储内容

0

01

未锁定

hash code(31),年龄(4)

1

01

偏向锁

线程ID(54),时间戳(2),年龄(4)

00

轻量级锁

栈中锁记录的指针(64)

10

重量级锁

monitor的指针(64)

11

GC标记

空,不需要记录信息

此处,有几点要注意:

如果对象没有重写hashcode方法,那么默认是调用os::random产生hashcode,可以通过System.identityHashCode获取;os::random产生hashcode的规则为:next_rand = (16807seed) mod (2*31-1),因此可以使用31位存储;另外一旦生成了hashcode,JVM会将其记录在markword中;

GC年龄采用4位bit存储,最大为15,例如MaxTenuringThreshold参数默认值就是15;

当处于轻量级锁、重量级锁时,记录的对象指针,根据JVM的说明,此时认为指针仍然是64位,最低两位假定为0;当处于偏向锁时,记录的为获得偏向锁的线程指针,该指针也是64位;

We assume that stack/thread pointers have the lowest two bits cleared.

ObjectMonitor* monitor() const {

assert(has_monitor(), "check");

// Use xor instead of &~ to provide one extra tag-bit check.

return (ObjectMonitor*) (value() ^ monitor_value);//monitor_value=2,value最右两位为10,因此异或之后最右两位为0

}

JavaThread* biased_locker() const {

assert(has_bias_pattern(), "should not call this otherwise");

return (JavaThread*) ((intptr_t) (mask_bits(value(), ~(biased_lock_mask_in_place | age_mask_in_place | epoch_mask_in_place))));

//~(biased_lock_mask_in_place | age_mask_in_place | epoch_mask_in_place)为11111111111111111111110010000000,计算后的结果中,低10位全部为0;

}

由于java中内存地址都是8的倍数,因此可以理解为最低3bit为0,因此假设轻量级和重量级锁的最低2位为0是成立的;但为什么偏向锁的最低10位都是0?查看markOop.hpp文件,发现有这么一句话:

// Alignment of JavaThread pointers encoded in object header required by biased locking

enum { biased_lock_alignment &#61; 2 <<(epoch_shift &#43; epoch_bits)

//epoch_shift&#43;epoch_bits&#xff1d;10

};

thread.hpp中重载了operator new:

void* operator new(size_t size) { return allocate(size, true); }

// &#61;&#61;&#61;&#61;&#61;&#61;&#61; Thread &#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;

// Support for forcing alignment of thread objects for biased locking

void* Thread::allocate(size_t size, bool throw_excpt, MEMFLAGS flags) {

if (UseBiasedLocking) {

const int alignment &#61; markOopDesc::biased_lock_alignment;//10

size_t aligned_size &#61; size &#43; (alignment - sizeof(intptr_t));

void* real_malloc_addr &#61; throw_excpt? AllocateHeap(aligned_size, flags, CURRENT_PC)

: os::malloc(aligned_size, flags, CURRENT_PC);

void* aligned_addr &#61; (void*) align_size_up((intptr_t) real_malloc_addr, alignment);

assert(((uintptr_t) aligned_addr &#43; (uintptr_t) size) <&#61;

((uintptr_t) real_malloc_addr &#43; (uintptr_t) aligned_size),

"JavaThread alignment code overflowed allocated storage");

if (TraceBiasedLocking) {

if (aligned_addr !&#61; real_malloc_addr)

tty->print_cr("Aligned thread " INTPTR_FORMAT " to " INTPTR_FORMAT,

real_malloc_addr, aligned_addr);

}

((Thread*) aligned_addr)->_real_malloc_address &#61; real_malloc_addr;

return aligned_addr;

} else {

return throw_excpt? AllocateHeap(size, flags, CURRENT_PC)

: os::malloc(size, flags, CURRENT_PC);

}

}

如果开启了偏移锁,在创建线程时&#xff0c;线程地址会进行对齐处理&#xff0c;保证低10位为0

实例数据

实例数据中主要包括对象的各种成员变量&#xff0c;包括基本类型和引用类型&#xff1b;static类型的变量会放到java/lang/Class中&#xff0c;而不会放到实例数据中&#xff1b;

对于引用类型的成员(包括string)&#xff0c;存储的指针&#xff1b;对于基本类型&#xff0c;直接存储内容&#xff1b;通常会将基本类型存储在一起&#xff0c;引用类型存储在一起&#xff1b;

例如类Test的成员定义如下:

private static Test t1&#61;new Test();

private Test t2;

private int a&#61;5;

private Integer b&#61;7;

private String c&#61;"112";

private BigDecimal d&#61;new BigDecimal("5");

private long e&#61;9l;

dc00b7058da6d6e159b328731e1450b6.png

body.png

可以看到long e、int a为基本类型&#xff0c;存储在一起&#xff1b;其它的引用类型存储在一起&#xff1b;int占用4bytes,不足8bytes,自动补足到8bytes;

链接&#xff1a;https://www.jianshu.com/p/ec28e3a59e80

原文&#xff1a;https://www.cnblogs.com/tiancai/p/12630305.html



推荐阅读
  • JavaBean和Map 转换 用反射方法实现
    由于JavaBean(实体类)结构与Map类似,我们可以把JavaBean与Map进行转换 ... [详细]
  • 本文整理了Java中com.jme3.math.Vector4f.hashCode()方法的一些代码示例,展示了Vector4f.hashCode() ... [详细]
  • Lodash中文文档(v3.10.1)–“Collection”要领TranslatedbyPeckZegOriginalDocs:Lodashv3.10.1Docs乞助翻译文档的 ... [详细]
  • 1、创建高级对象使用构造函数来创建对象构造函数是一个函数,调用它来例示并初始化特殊类型的对象。可以使用new关键字来调用一个构造函数。下面给出了使用构造函数的新示例。 ... [详细]
  • 1、对于List而言,要不然就使用迭代器,要不然就从后往前删除,从前往后删除会出现角标越界。因为我List有两个remove方法,一个是int作为形参(删除指定位置的元素),一个是 ... [详细]
  • 在JAVA中专门设计了一组类,他们实现了各种各样的数据存储,这种专门用来存储其他对象的类,被称为容器类,这组类和接口的设计结构也被称为集合框架(CollectionFramework)。JAVA集 ... [详细]
  • 本文整理了Java中com.fasterxml.jackson.databind.JavaType.withContentType()方法的一些代码示例,展示了 ... [详细]
  • *变量的赋值变量是基本数据类型时:此时赋值的是变量所保存的数据值变量是引用数据类型时:此时赋值的是变量所保存的数据的地址值方法中参数的传递机制方法必须 ... [详细]
  • IntelliJ IDEA 卡成球了?
    在和同事的一次讨论中发现,对IntelliJIDEA内存采用不同的设置方案,会对IDE的速度和响应能力产生不同的影响。Don’tbeaScroogeandgiveyourIDEso ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 漫画:位运算系列篇(只出现一次的数字)
    今天是小浩算法“365刷题计划”第62天。仍然分享一道关于位运算颇为简单的题型,同时,从明天开始将会提高难度,大家做好准备。01PARTS ... [详细]
  • 在开发四国军棋的游戏中,通过flex联机游戏开发-四国军棋游戏(五)-提炼棋类开发api,我们提炼出了第一个关于棋类游戏开发的api-FlexChessAPI,这个a ... [详细]
  • 序本文主要研究一下nacosServiceManager的removeInstanceServiceManagernacos-1.1.3namingsrcmainjavacomal ... [详细]
  • 开发笔记:Java多线程深度探索
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java多线程深度探索相关的知识,希望对你有一定的参考价值。 ... [详细]
author-avatar
第一城的呀呀_836
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有