注册
|
登录
发帖
热搜
活动
交友
discuz
论坛
BBS
翼度工具
翼度网址导航
开发工具
Linux命令速查
网页设计配色表
在线制作icon
颜色代码选取器
翼度科技
»
论坛
›
编程开发
›
.net
›
查看内容
返回列表
发新帖
.NET对象的内存布局
我叫老中医
我叫老中医
当前离线
积分
24
8
主题
8
帖子
24
积分
新手上路
新手上路, 积分 24, 距离下一级还需 26 积分
新手上路, 积分 24, 距离下一级还需 26 积分
积分
24
发消息
显示全部楼层
在.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个字节是填充。这种布局方式有效地减少了填充带来的空间浪费,并可能提高内存访问效率。
来源:
https://www.cnblogs.com/yyfh/archive/2023/08/10/17621881.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
本帖子中包含更多资源
您需要
登录
才可以下载或查看,没有账号?
立即注册
x
上一篇:
WPF实现类似ChatGPT的逐字打印效果
下一篇:
Winform跨线程访问UI
发表于 2023-8-11 00:07:23
举报
回复
使用道具
分享
返回列表
发新帖
本版积分规则
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
立即注册
快速回复
快速回复
返回顶部
返回顶部
返回列表
返回列表