JUC多并发编程 对象内存布局

news2024/9/28 1:22:54

对象的内存布局简介

在 Hotspot 虚拟机里,对象在堆内存中存在布局可划分为三个部分: 对象头(Header), 实例数据(Instance Data) 和对齐填充(Padding 保证8字节位数)

对象头

  • 对象标记 MarkWord, 在64位操作系统中, Mark Word 占8个字节, 类型占 8个字节,一共 16个字节
  • GC 年龄采用 4 位 bit 存储, 最大为 15, MaxTenuringThreshold = 15

Mark Word 标记:

存储内容标志位状态
对象哈希码、对象分代年龄01未锁定
指向锁记录的指针00轻量级锁定
指向重量级锁的指针10膨胀(重量级锁)
空、不需要记录信息11GC 标记
偏向线程ID、偏向时间戳、对象分代年龄01可偏向

Mark Word的存储结构:

锁状态25bit31bit1bit4bit1bit2bit
cms_free分代年龄偏向锁锁标志位
无锁unusedhashCode001
偏向锁ThreadID(54 bit) Epoch(2bit)101
轻量级锁指向栈中的锁的记录的指针00
重量级锁指向重量级锁的指针10
GC 标志11

类元数据(类型指针):

  • 对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例

实例数据

  • 存放类的属性(Field)数据信息,包括父类的属性信息

对齐填充

  • 虚拟机要求对象起始地址必须是8的字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐这部分内存按 8 字节补充对齐

实例代码:

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;

public class JOLDemo {
    public static void main(String[] args){

//        // VM 的细节详细情况
//        System.out.println(VM.current().details());
//        // 所有的对象分配的字节都是 8 的整数倍
//        System.out.println(VM.current().objectAlignment());

        // OFFSET 偏移量,也就是这个字段位置所占用的 byte 数
        // SIZE 后面类型的字节大小
        // TYPE 是 Class 中定义的类型
        // DESCRIPTION 类型的描述
        // TYPE 在内存中的值
        // 前两行是 MarkWord 8 字节, 第三行是 类型指针 4 字节
        // 对象头情景1
        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());

        // 对象头 情景2
        Customer c1 = new Customer();
        System.out.println(ClassLayout.parseInstance(c1).toPrintable());

    }
}

class Customer{
    int id;
    boolean flag = false;
}

压缩指针:

  • java -XX: +PrintCommandLineFlags-version 展示默认适用情况
  • 默认开启压缩指针(-XX:+UseCompressedClassPointers), 12 + 4(对齐填充) 一个对象 16个字节
  • 关闭压缩指针(-XX:-UseCompressedClassPointers),Mark Word 占8个字节, 类型占 8个字节,一共 16个字节

底层代码

oop.hpp:

// oop.hpp
class oopDesc {
  friend class VMStructs;
 private:
  volatile markOop  _mark;
  union _metadata {
    Klass*      _klass;
    narrowKlass _compressed_klass;
  } _metadata;

  // Fast access to barrier set.  Must be initialized.
  static BarrierSet* _bs;

 public:
  markOop  mark() const         { return _mark; }
  markOop* mark_addr() const    { return (markOop*) &_mark; }

  void set_mark(volatile markOop m)      { _mark = m;   }

  void    release_set_mark(markOop m);
  markOop cas_set_mark(markOop new_mark, markOop old_mark);

  // Used only to re-initialize the mark word (e.g., of promoted
  // objects during a GC) -- requires a valid klass pointer
  void init_mark();

  Klass* klass() const;
  Klass* klass_or_null() const volatile;
  Klass** klass_addr();
  narrowKlass* compressed_klass_addr();

  void set_klass(Klass* k);

  // For klass field compression
  int klass_gap() const;
  void set_klass_gap(int z);
  // For when the klass pointer is being used as a linked list "next" field.
  void set_klass_to_list_ptr(oop k);
  oop list_ptr_from_klass();

  // size of object header, aligned to platform wordSize
  static int header_size()          { return sizeof(oopDesc)/HeapWordSize; }

  // Returns whether this is an instance of k or an instance of a subclass of k
  bool is_a(Klass* k)  const;
  ......
}

markOop.hpp:

#ifndef SHARE_VM_OOPS_MARKOOP_HPP
#define SHARE_VM_OOPS_MARKOOP_HPP

#include "oops/oop.hpp"

// The markOop describes the header of an object.
//
// Note that the mark is not a real oop but just a word.
// It is placed in the oop hierarchy for historical reasons.
//
// Bit-format of an object header (most significant first, big endian layout below):
//
//  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)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/487349.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

单词搜索I II/前缀树

79单词搜索 思路: 注意: 我自己在写 for i in range(m):for j in range(n):# 对每一个格子都从头开始搜索if self.__search_word(board, word, 0, i, j, marked, m, n):return True这一段的时候,就写成了: 这一段代码是…

Mysql 主从 读写分离

目录 0 课程视频 1 概述 1.1原理 -> 传二进制日志到 从库 -> 执行 1.2 作用 1.2.1 主库崩 从库上 1.2.2 读写分离 1.2.3 从库备份 -> 备份完 再用 二进制日志同步 2 搭建 2.1 防火墙 端口号开启 2.2 主库设置 2.2.1 修改配置文件 -.> /etc/my.cnf 2.2…

高压放大器模块在平面水声压电换能器研究中的应用

实验名称:平面水声压电换能器的制备与性能研究 研究方向:压电换能器 实验原理: 压电换能器是能够发射和接收超声波的电声转换器件,按照不同的标准,换能器可分为不同的种类。按照功能可分为发射型、接收型和收发两用…

亚马逊下单需要什么条件?(养号干货知识)

混迹亚马逊的老手都知道,测评向来都是最有效,最快速的推广方式,给自己商品做点销量,优化一下listing,留一下一些优质评论,甚至于打压一下竞品,帮自己商品解个围。 养号环境四大步: …

定制海报、AI扣人像小程序

大家好,我是csdn的博主:lqj_本人 这是我的个人博客主页: lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主lqj_本人擅长微信小程序,前端,python,等方面的知识https://blog.csdn.net/lbcyllqj?spm=1011.2415.3001.5343哔哩哔哩欢迎关注:小淼Develop 小淼Develop的个…

nakamichi车机中控屏密码破解(开发者选项密码、usb主从模式切换密码)

版本 Android11 平台 mtk 打开开发者选项,连续点击系统版本号会弹出密码框确认 这个默认密码这台设备并没有配置,而是动态的 默认密码 SystemProperties.get(“ro.sys.developer”, “”); 动态根据设备当前日前来生成的格式为 yyyy.MM.dd 所以上面的…

Node框架 【Koa】开发框架、路由

文章目录 🌟前言🌟开发框架🌟应用程序🌟应用程序Koa类🌟应用对象(app)的方法🌟app.use(function)🌟app.listen(...) 🌟应用程序设置 🌟上下文(Context) 🌟路由…

电脑c盘满了变成红色了怎么清理?看看这7个方法

当C盘出现红色标识提示时,表示该分区的可用存储空间已经极度不足,可能会影响系统稳定性和性能。如果您需要清理C盘并腾出更多的存储空间,可以采取以下措施: 一、电脑c盘7种清理方法 方法1:清空回收站 演示机型&#…

pytorch优化器——add_param_group()介绍及示例、Yolov7 优化器代码示例

系列文章目录 基础函数2——enumerate()、hasattr()、isinstance() pytorch学习率设置——optimizer.param_groups、对不同层设置学习率、动态调整学习率。 文章目录 系列文章目录前言1、关于pytorch优化器2、add_param_group()3、pytorch优化器4、pytorch优化器测试总代码5、…

如何保证 RabbitMQ 的消息可靠性

前言 项目开发中经常会使用消息队列来完成异步处理、应用解耦、流量控制等功能。虽然消息队列的出现解决了一些场景下的问题,但是同时也引出了一些问题,其中使用消息队列时如何保证消息的可靠性就是一个常见的问题。如果在项目中遇到需要保证消息一定被…

大数据技术之Hadoop-入门

第1章 Hadoop概述 1.1 Hadoop是什么 分布式:多台服务器共同完成某一项任务。 1.2 Hadoop发展历史 1.3 Hadoop三大发行版本 Hadoop三大发行版本:Apache、Cloudera、Hortonworks。 Apache版本最原始(最基础)的版本&#xff0c…

【三十天精通Vue 3】第二十六天 Vue3 与 TypeScript 最佳实践

✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: 三十天精通 Vue 3 文章目录 引言一、为什么使用TypeScript?二、Vue 3和TypeScript…

Golang每日一练(leetDay0055)

目录 159.至多包含两个不同字符的最长子串 Longest-substring-with-at-most-two-distinct-characters 🌟🌟 160. 相交链表 Intersection-of-two-linked-lists 🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 …

Stable Diffusion +ChatGPT+文本转语音+剪映制作视频

目录 chatgpt免费体验入口网址 模型下载 huggingface.co civitai.com 使用Deliberate模型案例 StableDeffusion做的图片,chatGPT出的文案,微软文本转语音配的音,使用剪映做的视频 chatgpt免费体验入口网址 http://chat.xutongbao.top …

【Java数据结构】顺序表、队列、栈、链表、哈希表

顺序表 定义 存放数据使用数组但是可以编写一些额外的操作来强化为线性表&#xff0c;底层依然采用顺序存储实现的线性表&#xff0c;称为顺序表 代码实现 创建类型 先定义一个新的类型 public class ArrayList<E> {int capacity 10; //顺序表的最大容量int size …

UNIX环境高级编程——信号

10.1 引言 信号是软件中断&#xff1b;信号提供了一种处理异步事件的方法。 10.2 信号概念 每个信号都有一个名字&#xff0c;这些名字都以3个字符SIG开头&#xff1b;在头文件<signal.h>中&#xff0c;信号名都被定义为正整数常量&#xff08;信号编号&#xff09;&a…

架构设计-高性能篇

大家好&#xff0c;我是易安&#xff01;今天我们谈一谈架构设计中的高性能架构涉及到的底层思想。本文分为缓存架构&#xff0c;单服务器高性能模型&#xff0c;集群下的高性能模型三个部分&#xff0c;内容很干&#xff0c;希望你仔细阅读。 高性能缓存架构 在某些复杂的业务…

代码审计笔记之java多环境变量设置

在做java代码审计时&#xff0c;为了要成功运行目标环境&#xff0c;时长要对于jdk版进行切换&#xff0c;且在装多个jdk时还时长会遇到安装配置后环境变量不生效的情况&#xff0c;下文介绍&#xff1b; 1、为什么安装了新的jdk&#xff0c;有的时候环境变量中的jdk版本确还是…

如何设计出好的测试用例?

软件测试培训之如何设计出好的测试用例? 一句话概括&#xff1a;对被测软件的需求有深入的理解。 深入理解被测软件需求的最好方法是&#xff0c;测试工程师在需求分析和设计阶段就开始介入&#xff0c;因为这个阶段是理解和掌握软件的原始业务需求的最好时机。 只有真正理解了…

【VAR模型 | 时间序列】帮助文档:VAR模型的引入和Python实践(含源代码)

向量自回归 (VAR) 是一种随机过程模型&#xff0c;用于捕获多个时间序列之间的线性相互依赖性。 VAR 模型通过允许多个进化变量来概括单变量自回归模型&#xff08;AR 模型&#xff09;。 VAR 中的所有变量都以相同的方式进入模型&#xff1a;每个变量都有一个方程式&#xff…