首页 > 系统相关 >.NET对象的内存布局

.NET对象的内存布局

时间:2023-08-16 21:11:06浏览次数:38  
标签:字节 对象 布局 SampleStruct 内存 NET public

在.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字节,再加上至少4字节的实例字段空间(即使没有实例字段,也会分配这部分空间以满足内存对齐的要求),因此每个对象至少占用12字节的空间。在64位系统中,由于指针的大小是8字节(但只有后4个字节被使用),64位系统中需要8字节来保证内存对齐,每个对象至少占用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)  |
|===========================|
PYTHON 复制 全屏

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

标签:字节,对象,布局,SampleStruct,内存,NET,public
From: https://www.cnblogs.com/chinasoft/p/17636206.html

相关文章

  • 一个可将执行文件打包成Windows服务的.Net开源工具
    Windows服务一种在后台持续运行的程序,它可以在系统启动时自动启动,并在后台执行特定的任务,例如监视文件系统、管理硬件设备、执行定时任务等。今天推荐一个可将执行文件打包成Windows服务的工具,方便我们封装第三个的软件。项目简介winsw一个基于.Net开发的开源项目,可以帮助开发......
  • 内存管理
    虚拟存储空间的大小受到计算机地址位宽因素限制。页面置换算法先进先出页面置换算法(FIFO)思想:总是把最先装入内存的一页调出会产生贝莱迪异常(BeladyAnomaly)现象,分配给进程的物理页面数增加时,缺页次数反而增加 最近最少使用页面置换算法(LRU)思想:选择距离现在最长时间内没有被访问的......
  • tonardo做web服务器播放大视频内存泄露问题的解决
    之前为了实现websocket来完成网页的推送,所以使用了tonardo作为web服务器。但是如果网页中含有视频插件的话,特别是经常要播放大视频的话,在linux环境下,经常发现python进程会莫名其妙的死掉。通过内存检测命令动态查看,发现python进程的内存占用一直居高不下,并且需要启用缓存才行。直到......
  • rails3学习系列(二)MVC---NetworkError: 500 Internal Server Error
    当我创建了一个control文件:backup_for_sqlserver_controller.rb              classBackupForSqlServerController<ScreenController                   defconfig_wizard                   end          ......
  • facenet + fiass 实现人脸识别
    人脸检测使用MTCNN模型的detech方法获取人脸坐标人脸识别使用MTNN模型获取人脸特征使用InceptionResnetV1模型获取512个人脸特征向量使用获取的人脸特征向量与已知人脸向量对比,已知人脸向量存储在fiass相似性搜索库中fromfacenet_pytorchimportMTCNN,InceptionResnet......
  • RNN,LSTM,ResNet
    神经网络的梯度更新反向传播算法:神经网络中加速计算参数梯度值的方法    梯度下降算法->随机梯度下降、动量随机梯度   凸优化:几何意义,任取一个集合中的两点练成一条线段,如果这条线段完全落在该集合中,那么这个集合就是凸集BN训练测试:BN本质上是解决传播过程中......
  • .NET Core6.0配置JWT
    环境 ASP.NETCoreWebAPIJWT的一些讲解和与Session的区别俺就不多说了可以去官方文档了解一下直接上代码简单粗暴(以下操作都是在ASP.NETCoreWebAPI进行操作)第一步:引入一个NuGet包  根据自己.NET版本选择对应的版本号 第二步:在appsettings.json配置一些信息"A......
  • Flutter 各种布局方式汇总
    本文会列举一组Flutter布局代码示例。因为Flutter相对于Android原生的layout布局或者是Compose布局,还是不太一样。如果不了解到全部的布局方式,在一些应用场景,就不能选择到最佳的布局方式来实现当前的需求。目录:RowandColumnIntrinsicWidthandIntrinsicHeightStackExp......
  • 代码性能测试 运行时间和占用内存
    运行时间用内置的`%time`和`%timeit`前者运行1次的时间,后者运行多次的平均值,放在单行代码前。要测试整个单元格,就是`%%time`和`%%timeit`,放在单元格的顶部。占用内存要用到第三方库memory_profiler,然后在单元格中导入 %load_extmemory_profiler在需要测量内存的代码单元格......
  • C# .NET6 WPF 依赖注入
    入口文件:App.xaml.csusingMicrosoft.EntityFrameworkCore;usingMicrosoft.Extensions.Configuration;usingMicrosoft.Extensions.DependencyInjection;usingSerilog;usingSystem;usingSystem.IO;usingSystem.Text;usingSystem.Windows;namespaceDemo{......