.NET对象的内存布局

news/2024/4/15 15:04:32

在.NET中,理解对象的内存布局是非常重要的,这将帮助我们更好地理解.NET的运行机制和优化代码,本文将介绍.NET中的对象内存布局。
.NET中的数据类型主要分为两类,值类型和引用类型。值类型包括了基本类型(如int、bool、double、char等)、枚举类型(enum)、结构体类型(struct),它们直接存储值。引用类型则包括了类(class)、接口(interface)、委托(delegate)、数组(array)等,它们存储的是值的引用(数据在内存中的地址)。

值类型的内存布局

值类型的内存布局是顺序的,并且是紧凑的。例如,定义的结构体SampleStruct,其中包含了四个int类型字段,每个字段占用4个字节,因此整个SampleStruct结构体在内存中占用16个字节。

public struct SampleStruct
{public int Value1; public int Value2;public int Value3;public int Value4;
}

它在内存中的布局如下:

结构的内存布局

引用类型的内存布局

引用类型的内存布局则更为复杂。首先,每个对象都有一个对象头,其中包含了同步块索引和类型句柄等信息。同步块索引用于支持线程同步,类型句柄则指向该对象的类型元数据。然后,每个字段都按照它们在源代码中的顺序进行存储。

例如,下面的类:

public class SampleStruct
{public int Value1; public int Value2;public int Value3;public int Value4;
}

它在内存中的布局如下:

类的内存布局

在.NET中,每个对象都包含一个对象头(Object Header)和一个方法表(Method Table)。

  • 对象头:存储了对象的元信息,如类型信息、哈希码、GC信息和同步块索引等。对象头的大小是固定的,无论对象的大小如何,对象头都只占用8字节(在64位系统中)或4字节(在32位系统中)。
  • 方法表:这是.NET用于存储对象的类型信息和方法元数据的数据结构。每个对象的类型,包括其类名、父类、接口、方法等都会被存储在MethodTable中。

在32位系统中,对象头和方法表指针各占4字节,因此每个对象至少占用12字节的空间(不包括对象的实例字段)。在64位系统中,由于指针的大小是8字节,但只有后4个字节被使用,每个对象至少占用24字节的空间(不包括对象的实例字段)。

每个.NET对象的头部都包含一个指向同步块的索引(Sync Block Index)和一个指向类型的指针(Type Pointer)。

  • Sync Block Index: 是一个指向同步块的索引。同步块用于存储对象锁定和线程同步信息的结构。当你对一个对象使用lock关键字或Monitor类进行同步时,会用到同步块。如果对象未被锁定,那么这个索引通常是0。
  • Type Pointer: 是一个指向对象类型MethodTable的指针。

字段按照源代码中的顺序存储。值类型的字段直接存储值,引用类型的字段存储的是对值的引用,即指针。在32位系统中,指针占用4个字节,而在64位系统中,指针占用8个字节。可以通过StructLayoutAttribute来自定义.NET中的对象内存布局。例如,通过Sequential参数可以保证字段的内存布局顺序与源代码中的相同,或者通过Explicit参数来手动指定每个字段的偏移量。实例成员需要8字节对齐,即使没有任何成员,也需要8个字节。

堆上分配对象的最小占用空间

// The generational GC requires that every object be at least 12 bytes in size.
#define MIN_OBJECT_SIZE     (2*TARGET_POINTER_SIZE + OBJHEADER_SIZE)

进阶

在.NET中,对象在内存中的布局是由运行时环境自动管理的。而对于结构体,我们可以通过System.Runtime.InteropServices命名空间的StructLayout属性来设置其在内存中的布局方式。

  • LayoutKind.Auto:这是类和结构的默认布局方式。在这种方式下,运行时会自动选择合适的布局。
  • LayoutKind.Sequential:在这种方式下,字段在内存中的顺序将严格按照它们在代码中的声明顺序。
  • LayoutKind.Explicit:这种方式允许你显式定义每个字段在内存中的偏移量。

以下是一个例子,它定义了一个名为SampleStruct的结构体,并使用了StructLayout属性来设置其布局方式。

[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct SampleStruct
{public byte X;public double Y;public int Z;
}

在这个例子中,我们可以使用ObjectLayoutInspector库来查看SampleStruct在内存中的布局。

void Main()
{TypeLayout.PrintLayout<SampleStruct>();
}

上述代码的输出如下,值得注意的是,使用System.Runtime.InteropServices命名空间的StructLayout属性将结构的布局设置为Sequential。这意味着在内存中结构的布局是按照在结构中声明的字段的顺序进行的。

Type layout for 'SampleStruct'
Size: 24 bytes. Paddings: 11 bytes (%45 of empty space)
|===========================|
|     0: Byte X (1 byte)    |
|---------------------------|
|   1-7: padding (7 bytes)  |
|---------------------------|
|  8-15: Double Y (8 bytes) |
|---------------------------|
| 16-19: Int32 Z (4 bytes)  |
|---------------------------|
| 20-23: padding (4 bytes)  |
|===========================|

这里,我们可以看到SampleStruct在内存中的具体布局:首先是X字段(占用1个字节),然后是7个字节的填充,接着是Y字段(占用8个字节),然后是Z字段(占用4个字节),最后是4个字节的填充。总共占用24个字节,其中11个字节是填充。

这个例子中,我们将结构体SampleStruct的布局设置为Auto。在这种方式下,运行时环境会自动进行布局,可能会对字段进行重新排序,或在字段之间添加填充以使他们与内存边界对齐。

[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Auto)]
public struct SampleStruct
{public byte X;public double Y;public int Z;
}

如下所示再来检查SampleStruct在内存中的布局:

Type layout for 'SampleStruct'
Size: 16 bytes. Paddings: 3 bytes (%18 of empty space)
|===========================|
|   0-7: Double Y (8 bytes) |
|---------------------------|
|  8-11: Int32 Z (4 bytes)  |
|---------------------------|
|    12: Byte X (1 byte)    |
|---------------------------|
| 13-15: padding (3 bytes)  |
|===========================|

从输出结果可以看出,运行时环境对字段进行了重新排序,并在字段之间添加了填充。首先是Y字段(占用8个字节),然后是Z字段(占用4个字节),接着是X字段(占用1个字节),最后是3个字节的填充。总共占用16个字节,其中3个字节是填充。这种布局方式有效地减少了填充带来的空间浪费,并可能提高内存访问效率。


http://www.ppmy.cn/news/1026803.html

相关文章

VB+sql小型超市管理系统设计与实现

1、项目计划 1.1系统开发目的 (1)大大提高超市的运作效率; (2)通过全面的信息采集和处理,辅助提高超市的决策水平; (3)使用本系统,可以迅速提升超市的管理水平,为降低经营成本, 提高效益,增强超市扩张力, 提供有效的技术保障。 1.2背景说明 21世纪,超市的…

23款奔驰AMG GT50更换原厂运动排气系统,战斗感立马提升了

改装运动排气&#xff0c;原车中控的按键组也是需要更换的。与原车按键相比&#xff0c;只是多了一个排气的控制按键&#xff0c;也正是这个按键&#xff0c;能让车辆可静可怒&#xff0c;安静与怒吼就在一键之间。

【LeetCode 算法】Merge k Sorted Lists 合并 K 个升序链表

文章目录 Merge k Sorted Lists 合并 K 个升序链表问题描述&#xff1a;分析代码Heap Tag Merge k Sorted Lists 合并 K 个升序链表 问题描述&#xff1a; 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合并…

Linux命令行参数前加 - -- 或 不加- 的区别

Linux命令行中参数的表示方式并没有统一的官方规定,但是有一些常见的惯例和约定,这些惯例大多是由各个命令的开发者和社区共同形成的。 短参数:单个减号 - ,后面加单个字母、 如果选项需要加参数的时候,紧跟在选项后面(或者加空格) 例如: ls -a gcc -v mysql -u…

关系型数据库MySQL及其优化

写在前面 本文看下MySQL的基础内容以及常见的优化方式。 1&#xff1a;MySQL基础内容 1.1&#xff1a;什么是关系型数据库 以二维的数据格式来存储数据的数据库叫做关系型数据库&#xff0c;其中关系包括一对一&#xff0c;一对多&#xff0c;多对多&#xff0c;都通过二位…

java下载JDK

1.去官网下载 https://www.oracle.com/java/technologies/javase-downloads.html 2.点击 傻瓜式安装 注意选择版本跟电脑系统就行 下载后文件的作用

数据结构与算法-数组(附阿里面试题)

一 面试经典&#xff1a; 给你一个文件里面包含全国人民&#xff08;14亿&#xff09;的年龄数据&#xff08;0~180&#xff09;&#xff0c;现在要你统计每一个年龄 有多少人&#xff1f; 给定机器为 单台2CPU2G内存。不得使用现成的容器&#xff0c;比如map等。&am…

BOLT- 识别和优化热门的基本块

在BOLT中&#xff0c;识别和优化热门的基本块之所以关键&#xff0c;是因为BOLT的主要目标是优化程序以更好地利用硬件特性&#xff0c;特别是指令缓存&#xff08;ICache&#xff09;。以下是BOLT如何识别和优化热门基本块的流程&#xff1a; 收集性能数据: BOLT开始的时候并不…

多线程中常见的成员方法

1.常见的成员方法 如果没有给线程设置名字&#xff0c;线程也是有默认名字的&#xff0c;格式&#xff1a; Thread-X&#xff08;X序号&#xff0c;从0开始的&#xff09; 2.创建名字的线程构造 用构造方法给线程设置名字 当JVM虚拟机启动之后&#xff0c;会自动的启动多条…

Git全栈体系(四)

第七章 IDEA 集成 Git 一、配置 Git 忽略文件 1. Eclipse 特定文件 2. IDEA 特定文件 3. Maven 工程的 target 目录 4. 问题 4.1 为什么要忽略他们&#xff1f; 与项目的实际功能无关&#xff0c;不参与服务器上部署运行。把它们忽略掉能够屏蔽 IDE 工具之间的差异。 4.2 …

中科亿海微浮点数转换定点数

引言 浮点数转换定点数是一种常见的数值转换技术&#xff0c;用于将浮点数表示转换为定点数表示。浮点数表示采用指数和尾数的形式&#xff0c;可以表示较大范围的数值&#xff0c;但存在精度有限的问题。而定点数表示则采用固定小数点位置的形式&#xff0c;具有固定的精度和范…

SD-MTSP:杨氏双缝实验优化算法YDSE求解单仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)

一、杨氏双缝实验优化算法YDSE 杨氏双缝实验优化算法&#xff08;Young’s double-slit experiment optimizer&#xff0c;YDSE&#xff09;由Mohamed Abdel-Basset等人于2023年提出。 参考文献&#xff1a; [1]Mohamed Abdel-Basset, Doaa El-Shahat, Mohammed Jameel, Moha…

【JavaWeb】MySQL基础操作

1 通用语法规则 SQL语句可以单行或者多行书写&#xff0c;以分号结尾SQL语句不区分大小写&#xff0c;关键字建议使用大写单行注释 --注释内容&#xff08;通用&#xff09; # 注释内容&#xff08;MySQL独有&#xff09;多行注释 /* 注释内容 */ 2 语句 数据库 -- 查…

WebRTC基础知识

文章目录 基础概念NAT (Network Address Translation) 打洞STUN&#xff08;Session Traversal Utilities for NAT&#xff09;基于STUN协议的DDoS反射攻击 # TODO TURN&#xff08;Traversal Using Relays around NAT&#xff09;ICE&#xff08;Interactive Connectivity Est…

代码随想录算法训练营第55天|动态规划part12|309.最佳买卖股票时机含冷冻期、714.买卖股票的最佳时机含手续费、总结

代码随想录算法训练营第55天&#xff5c;动态规划part12&#xff5c;309.最佳买卖股票时机含冷冻期、714.买卖股票的最佳时机含手续费、总结 309.最佳买卖股票时机含冷冻期 309.最佳买卖股票时机含冷冻期 思路&#xff1a; 区别在第i天持有股票的当天买入的情况&#xff0c…

奶牛用餐 优先队列 java

&#x1f468;‍&#x1f3eb; 奶牛用餐 约翰的农场有 n n n 头奶牛&#xff0c;编号 1 s i m n 1 \\sim n 1simn。 每天奶牛们都要去食堂用餐。 食堂一共有 k k k 个座位&#xff0c;也就是说同一时间最多可以容纳 k k k 头奶牛同时用餐。 已知&#xff0c;第 i i i …

docker实现Nginx

文章目录 1.docker 安装2.docker环境实现Nginx 1.docker 安装 1.使用环境为红帽8.1,添加源 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo2.安装 yum install docker-ce docker-ce-cli containerd.io显示出错 Docker C…

20230812在WIN10下使用python3将SRT格式的字幕转换为SSA格式

20230812在WIN10下使用python3将SRT格式的字幕转换为SSA格式 2023/8/12 20:58 本文的SSA格式以【Batch Subtitles Converter(批量字幕转换) v1.23】的格式为准&#xff01; 1、 缘起&#xff1a;网上找到的各种各样的字幕转换软件/小工具都不是让自己完全满意&#xff01; 【都…

第五十一天

●响应式界面有四个层次&#xff1a; 1、同一页面在不同大小和比例上看起来都应该是舒适的&#xff1b; 2、同一页面在不同分辨率上看起来都应该是合理的&#xff1b; 4、同一页面在不同操作方式&#xff08;如鼠标和触屏&#xff09;下&#xff0c;体验应该是统一的&#x…

【前端二次开发框架关于关闭eslint】

前端二次开发框架关于关闭eslint 方法一方法二方法三方法四&#xff1a;以下是若想要关闭项目中的部分代码时&#xff1a; 方法一 在vue.config.js里面进行配置&#xff1a; module.exports {lintOnSave:false,//是否开启eslint保存检测 ,它的有效值为 true || false || err…
最新文章