当前位置: 首页 > news >正文

03. 对象的创建,存储和访问原理

文章目录

    • 01. 对象创建
      • 1.1 创建过程概览
      • 1.2 类加载检查
      • 1.3 为对象分配内存
      • 1.4 将内存空间初始化为零值
      • 1.5 设置对象的必要信息
      • 1.6 总结
    • 02. 对象的内存布局
      • 2.1 对象头区域
      • 2.2 实例数据区域
      • 2.3 对齐填充区域
      • 2.4 总结
    • 03. 对象的访问定位
    • 其他介绍
      • 01.关于我的博客

注:读者在阅读博客的过程中总结各个文章的知识,写了很多笔记。但是本文原作者的写作和总结已经很翔实了,因此本文绝大多数照搬原作者的写作,中间稍加自己的理解和修改。原文来源如下:

作者:Carson带你学Android
链接:https://juejin.cn/post/6844903681553334285

01. 对象创建

  • 在开发使用时,创建 Java 对象仅仅只是是通过关键字newA a = new A();,可是它真的这么简单吗?我想不是的,他是一个很复杂的过程。

1.1 创建过程概览

  • 对象创建的流程概览如下:

    • new指令启动流程。
    • 类加载检查
    • 为对象分配内存
    • 将内存空间初始化为零值
    • 对对象进行必要的设置
  • 下面我将对每个步骤进行讲解。

在这里插入图片描述

1.2 类加载检查

  • 我们,调用new的时候,知道new指令右侧是有一个参数的, 它是一个符号引用,我们要检查是否能在 常量池中 定位到该符号引用,未定位到,则说明类尚未加载,我们要进行类的加载机制。这个我们可以后续介绍。

如果没有,需要先执行相应的类加载过程

1.3 为对象分配内存

  • 现在我们类加载检查通过了,确定类已经被加载进来了。

  • 虚拟机将会在堆中为对象分配内存,即把一块确定大小的内存从 Java 堆中划分出来,对象所需内存的大小在类加载完成后便可完全确定。

  • 内存分配 根据 Java堆内存是否绝对规整 分为两种方式:指针碰撞 & 空闲列表

    怎么理解这里的规整和不规整?

    1. Java堆内存 规整:已使用的内存在一边,未使用内存在另一边
    2. Java堆内存 不规整:已使用的内存和未使用内存相互交错

    在这里插入图片描述

    • 指针碰撞:已使用内存在一边,未使用内存在另一边,中间有一个指针作为分界指示器,那么,分配对象内存 = 把指针向 未使用内存 移动一段 与对象大小相等的距离

        • 在这里插入图片描述
    • 空闲列表:虚拟机维护着一个 记录可用内存块 的列表,在分配时从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录

    那么Java堆为什么有时候规整,有时候不规整?

    Java堆是否规整 由所采用的垃圾收集器是否带有压缩整理功能决定。因此:

    1. 使用带复制和标记-整理算法的垃圾收集器时(如Serial、ParNew垃圾收集器),采用指针碰撞;
    2. 使用 标记-清除算法的垃圾收集器时(如 CMS垃圾收集器),采用空闲列表。
  • 可是对象在堆中分配是非常频繁的操作,而堆又是进程共享的,会存在并发情况下线程安全的问题。如,正在给对象A分配内存,指针还没有来得及修改,对象B又同时使用了原来的指针来分配内存。我们怎么解决这个问题呢?

    • 加锁?ok,这可以,这是最基础的解决方式。但是,效率较低,有没有其它更好的方式呢?有的,孩子,我们可以采用更细的颗粒度的。
    • 我们可以为每个线程在 Java堆中预先分配一小块内存(本地线程分配缓冲(Thread Local Allocation BufferTLAB)),哪个线程要分配内存,就在哪个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时才需要同步锁。

1.4 将内存空间初始化为零值

  • 内存分配完成后,虚拟机需要将分配到的内存空间初始化为零(不包括对象头),这保证了对象的实例字段在使用时可不赋初始值就直接使用(对应值 = 0)

1.5 设置对象的必要信息

  • 如,设置 这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头中

  • 至此,从 Java 虚拟机的角度来看,一个新的 Java对象创建完毕。但从 Java 程序开发来说,对象创建才刚开始,需要进行一些初始化操作。

1.6 总结

  • 下面用一张图总结 Java对象创建的过程
    • 在这里插入图片描述

02. 对象的内存布局

  • 那么在 Java 对象创建后,到底是如何被存储在Java内存里的呢?

  • 对象在 Java内存中的 存储布局 可分为三块:

    • 对象头 存储区域
    • 实例数据 存储区域
    • 对齐填充 存储区域
  • 在这里插入图片描述

  • 下面我会详细说明每一块区域。

2.1 对象头区域

此处存储的信息包括两部分:

  • 对象自身的运行时数据(Mark Word
  1. 如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等
  2. 该部分数据被设计成1个 非固定的数据结构 以便在极小的空间存储尽量多的信息(会根据对象状态复用存储空间)
  • 对象的类型指针
  1. 即对象指向它的类元数据的指针
  2. 虚拟机通过这个指针来确定这个对象是哪个类的实例
  • 如果对象是数组,那么在对象头中还必须有一块用于记录数组长度的数据

因为虚拟机可以通过普通Java对象的元数据信息确定对象的大小,但是从数组的元数据中却无法确定数组的大小。


2.2 实例数据区域

  • 存储对象的实例变量,这是对象真正有效的数据

2.3 对齐填充区域

  • 存储的信息:占位符,起到占位作用,当对象的大小不是8字节的整数倍,就需要通过对齐填充来补全。

为什么要补全呢?这不是白白浪费空间吗?

这涉及到底层的原理:

在程序员看来,内存是由一个个的字节组成。而CPU并不是这么看待的,CPU把内存当成是一块一块的,这里cpu的块是8字节大小。

假如有一个8字节大小的数据,它分为两种情况:

1、数据从0字节开始
2、数据从1字节开始

  • 当该数据是从0字节开始时,很CPU只需读取内存一次即可把这8字节的数据完全读取到寄存器中。
  • 当该数据是从1字节开始时,问题变的有些复杂,此时该数据不是位于内存读取边界上,这就是一类内存未对齐的数据。此时CPU先访问一次内存,读取0—7的数据进寄存器,并再次读取8—15的数据进寄存器,接着把0和9后续的的数据剔除,最后合并1- 9这8字节的数据进寄存器。对一个内存未对齐的数据进行了这么多额外的操作,大大降低了CPU性能。因此我们采用补全,损失一些空间,换取更高的执行效率?

2.4 总结

在这里插入图片描述
**

03. 对象的访问定位

  • 问:建立对象后,该如何访问对象呢?

实际上需访问的是 对象类型数据 & 对象实例数据

  • 答:Java程序 通过 栈上的引用类型数据(reference) 来访问Java堆上的对象

由于引用类型数据(reference)在 Java虚拟机中只规定了一个指向对象的引用,但没定义该引用应该通过何种方式去定位、访问堆中的对象的具体位置

所以对象访问方式取决于虚拟机实现。目前主流的对象访问方式有两种:

  • 句柄 访问
  • 直接指针 访问

具体请看如下介绍:很有意思。

在这里插入图片描述

其他介绍

01.关于我的博客

  • csdn:http://my.csdn.net/qq_35829566

  • 掘金:https://juejin.im/user/499639464759898

  • github:https://github.com/jjjjjjava

  • 简书:http://www.jianshu.com/u/92a2412be53e

  • 邮箱:[934137388@qq.com]

相关文章:

03. 对象的创建,存储和访问原理

文章目录 01. 对象创建1.1 创建过程概览1.2 类加载检查1.3 为对象分配内存1.4 将内存空间初始化为零值1.5 设置对象的必要信息1.6 总结 02. 对象的内存布局2.1 对象头区域2.2 实例数据区域2.3 对齐填充区域2.4 总结 03. 对象的访问定位其他介绍01.关于我的博客 注:读…...

机器学习-GBDT算法

目录 一. GBDT 核心思想 二. GBDT 工作原理 ​**(1) 损失函数优化** ​**(2) 负梯度拟合** ​**(3) 模型更新** 三. GBDT 的关键步骤 四. GBDT 的核心优势 ​**(1) 高精度与鲁棒性** ​**(2) 处理缺失值** ​**(3) 特征重要性分析** ​五. GBDT 的缺点 ​**(1) 训练…...

redis基础结构

title: redis基础结构 date: 2025-03-04 08:39:12 tags: redis categories: redis笔记 Redis入门 (NoSQL, Not Only SQL) 非关系型数据库 关系型数据库:以 表格 的形式存在,以 行和列 的形式存取数据,一系列的行和列被…...

【keil】一种将STM32的armcc例程转换为armclang的方式

【keil】一种将所有armcc例程转换为armclang的方式 改的原因第一步下载最新arm6第二步编译成功 第三步去除一些warning编译成功 我这边用armclang去编译的话,主要是freertos中的portmacro.h和port.c会报错 改的原因 我真的服了,现在大部分的单片机例程都…...

计算机视觉算法实战——表面缺陷检测(表面缺陷检测)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ ​​​ 1. 引言 表面缺陷检测是计算机视觉领域中的一个重要研究方向,旨在通过图像处理和机器学习技术自动检测产品表面的缺陷&…...

window下的docker内使用gpu

Windows 上使用 Docker GPU需要进行一系列的配置和步骤。这是因为 Docker 在 Windows 上的运行环境与 Linux 有所不同,需要借助 WSL 2(Windows Subsystem for Linux 2)和 NVIDIA Container Toolkit 来实现 GPU 的支持。以下是详细的流程: 一、环境准备 1.系统要求 Window…...

Modbus协议(TCP)

从今开始,会详细且陆续整理各类的通信协议,以便在需要且自身忘记的情况下,迅速复习。如有错误之处,还请批评指正。 一、Modbus协议的简述 Modbus协议作为应用层协议,基于主从设备模型,主设备负责请求消息&…...

虚拟系统配置实验报告

一、实验拓扑图 二、实验配置 要求一: 虚拟系统: 设置管理: 进行信息配置 R1配置 虚拟系统配置 a: b: c: 测试 a–>b: 检测...

Agentic系统:负载均衡与Redis缓存优化

摘要 本文在前文Agentic系统的基础上,新增负载均衡(动态调整线程数以避免API限流)和缓存机制(使用Redis存储搜索结果,减少API调用)。通过这些优化,系统在高并发场景下更加稳定高效。代码完整可…...

28-文本左右对齐

给定一个单词数组 words 和一个长度 maxWidth ,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本。 你应该使用 “贪心算法” 来放置给定的单词;也就是说,尽可能多地往每行中放置单词。必要时可…...

建筑兔零基础自学python记录39|实战词云可视化项目——章节分布10(上)

这次我们来制作《红楼梦》各章节的分布情况: 源代码: import pandas as pd import numpy as np import matplotlib.pyplot as pltdf_hlm pd.read_csv("hlm.txt", names["hlm_texts"]).dropna()df_hlm df_hlm[~df_hlm.hlm_texts.s…...

Impacket工具中的横向渗透利器及其使用场景对比详解

在渗透测试中,横向移动(Lateral Movement)是指攻击者在获得一个系统的控制权限后,通过网络进一步渗透到其他系统的过程。Impacket 是一款强大的渗透测试工具集,提供了多种实现横向渗透的脚本,常见的工具包括…...

基于java,SpringBoot和Vue的医院药房药品管理系统设计

摘要 随着医疗行业信息化的快速发展,高效、精准的医院药房药品管理对于提升医疗服务质量和医院运营效率至关重要。本文基于 Java 语言,采用 SpringBoot 框架和 Vue 框架进行医院药房药品管理系统的设计与研究。该系统以 SpringBoot 作为后端开发框架&am…...

MQ保证消息的顺序性

在消息队列(MQ)中保证消息的顺序性是一个常见的需求,尤其是在需要严格按顺序处理业务逻辑的场景(例如:订单创建 → 支付 → 发货)。 一、消息顺序性被破坏的原因 生产者异步/并行发送:消息可能…...

cmake、CMakeLists.txt、make、ninja

文章目录 一、概念0.cmake官网1.什么是cmake2.为什么使用cmake3.CMakeLists.txt 二、CMakeLists.txt语法:如何编写CMakeLists.txt,语法详解(0)语法基本原则(1)project关键字(2)set关键字(3)message关键字(4)add_executable关键字(5)add_subdirectory关键…...

数据结构与算法 计算机组成 八股

文章目录 数据结构与算法数组与链表的区别堆的操作红黑树定义及其原理 计算机组成int和uint的表示原码反码补码移码的定义?为什么用补码? 数据结构与算法 数组与链表的区别 堆的操作 红黑树定义及其原理 计算机组成 int和uint的表示 原码反码补码移…...

RoboBrain:从抽象到具体的机器人操作统一大脑模型

25年2月来自北大、北京智源、中科院自动化所等的论文“RoboBrain: A Unified Brain Model for Robotic Manipulation from Abstract to Concrete”。 目前的多模态大语言模型(MLLM) 缺少三项必备的机器人大脑能力:规划能力,将复杂…...

算法 之 前缀和 与 滑动窗口 与 背包问题 的差异(子数组之和为k问题)

文章目录 使用前缀和哈希表560.和为K的子数组525.连续数组2588.统计美丽子数组数目 子数组的定义是原来的数组当中连续的非空的序列,而我们的背包问题的选与不选的情况,对应的是这个非连续的情况,那么这种情况就要注意当然啦,对于线性的时间内…...

微电网协调控制器ACCU-100 分布式光伏 光储充一本化

安科瑞 华楠 18706163979 应用范围: 分布式光伏、微型风力发电、工商业储能、光储充一体化电站、微电网等领域。 主要功能: 数据采集:支持串口、以太网等多通道实时运行,满足各类风电与光伏逆变器、储能等 设备接入&#xff…...

IDEA入门及常用快捷键

IDEA是java常用的IDE。当run一个.java文件时,其实是经历了先编译为.class,再运行的过程。 在project文件夹中,out文件夹存储编译的.class文件,src文件夹存储.java代码文件。 设置自动导包 快捷键: 格式化快捷键&…...

electron打包结构了解

Electron 应用打包后的文件结构和内容取决于你使用的打包工具(如 electron-builder、electron-packager 等)以及目标操作系统(Windows、macOS、Linux)。以下是典型 Electron 应用打包后的文件结构和关键组成部分: 1. 基…...

03.06 QT

一、使用QSlider设计一个进度条&#xff0c;并让其通过线程自己动起来 程序代码&#xff1a; <1> Widget.h: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QThread> #include "mythread.h"QT_BEGIN_NAMESPACE namespace Ui {…...

Python中的常用库

一、collections collections是 Python 标准库中的一个模块&#xff0c;提供了一些专门的容器数据类型&#xff0c;能够帮助你更高效地处理常见的数据结构操作。 1、Counter Counter 是一个字典的子类&#xff0c;用于计数可哈希对象。它会统计对象的出现次数&#xff0c;并…...

马尔科夫不等式和切比雪夫不等式

前言 本文隶属于专栏《机器学习数学通关指南》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见《机器学习数学通关指南》 正文 统计概率的利剑&#xff1a;掌…...

护照阅读器在汽车客运站流程中的应用

在汽车客运站的日常运营里&#xff0c;如何高效服务旅客、保障出行安全是工作重点。护照阅读器作为精准身份识别的得力工具&#xff0c;在客运站的多个关键流程&#xff0c;如自助购票、柜台购票、安检以及行李托运中&#xff0c;发挥着不可小觑的作用&#xff0c;有力地提升了…...

CentOS 7 安装Nginx-1.26.3

无论安装啥工具、首先认准了就是官网。Nginx Nginx官网下载安装包 Windows下载&#xff1a; http://nginx.org/download/nginx-1.26.3.zipLinxu下载 wget http://nginx.org/download/nginx-1.26.3.tar.gzLinux安装Nginx-1.26.3 安装之前先安装Nginx依赖包、自行选择 yum -y i…...

Unity 使用NGUI制作无限滑动列表

原理&#xff1a; 复用几个子物体&#xff0c;通过子物体的循环移动实现&#xff0c;如下图 在第一个子物体滑动到超出一定数值时&#xff0c;使其放到最下方 --------------------------------------------------------------》 然后不停的循环往复&#xff0c;向下滑动也是这…...

linux中断调用流程(arm)

文章目录 ARM架构下Linux中断处理全流程解析&#xff1a;从硬件触发到驱动调用 ⚡**一、中断触发与硬件层响应** &#x1f50c;**1. 设备触发中断** &#x1f4e1; **二、CPU阶段&#xff1a;异常入口与上下文处理** &#x1f5a5;️**1. 异常模式切换** &#x1f504;**2. 跳转…...

基于Matlab的多目标粒子群优化

在复杂系统的设计、决策与优化问题中&#xff0c;常常需要同时兼顾多个相互冲突的目标&#xff0c;多目标粒子群优化&#xff08;MOPSO&#xff09;算法应运而生&#xff0c;作为群体智能优化算法家族中的重要成员&#xff0c;它为解决此类棘手难题提供了高效且富有创新性的解决…...

【网络安全】——协议逆向与频繁序列提取:从流量中解码未知协议

目录 引言 一、为什么要结合频繁序列提取&#xff1f; 二、四步融合分析法 步骤1&#xff1a;原始流量采集与预处理 步骤2&#xff1a;多粒度序列模式挖掘 层1&#xff1a;单包内字节级频繁项 层2&#xff1a;跨数据包的行为序列 步骤3&#xff1a;关键字段定位与结构假…...