C# Struct的内存布局
转载:http://www.csharpwin.com/csharpspace/10454r4891.shtml
问题:请说出以下struct的实例大小以及内存布局
struct Struct1
{
public byte a;
public short b;
public string c;
public int d;
} struct Struct2
{
public byte a;
public long b;
public byte c;
public string d;
} struct Struct3
{
byte a;
byte b;
long c;
} struct Struct4
{
byte a;
long b;
byte c;
}
一会再看答案,看看和你的理解是不是有很大的出入?其实struct和class的内存布局都是由StructLayoutAttribute的构造参数:LayoutKind枚举决定的,struct由编译器添加LayoutKind.Sequential,class由编译器添加的是LayoutKind.Auto。而Sequential通过实验数据可以总结如下:
1. 对于不带引用类型的struct:按照定义的顺序排列,内存布局和c,c++规则相同。比如:
Byte a;
Byte b;
Long c;
的大小是 a,b填充4字节,c填充8字节
Byte a
Long c
Byte b
的大小是 a填充8字节,c填充8字节,b填充8字节
2. 对于带有引用类型的struct:大于4字节的字段 -> 引用字段 -> 小于4字节的字段
对于小于4字节的字段按照大小排列,如果大小相同按照定义顺序,内存布局和规则1相同。不过这里有个需要注意的地方就是如果字段还是一个struct类型的,那么这个字段始终排在最后。
所以上面的答案是:
Struct1:c(4) -> d(4) -> b(2) ->a(2)
Struct2:b(8) -> d(4) -> a(1)c(1)填充2字节
Struct3: a(1)b(1)填充2字节 -> c(8)
Struct4:a(1)填充7字节->b(8)->c(1)填充7字节
如果你想亲自动手实验一下的话需要使用SOS.dll进行调试(关于SOS配置和使用入门的文章博客园上有很多)以struct1为例:
Struct1s1 = new Struct1();
s1.a = 1;
s1.b = 15;
s1.c = "c";
s1.d = 32;
.load sos
已加载扩展C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll
!clrstack -a
PDB symbol for mscorwks.dll not loaded
OS Thread Id: 0x15fc (5628)
ESP EIP
0041ee3c 03ba01aa Test_Console.Class12.Main()
LOCALS:
0x0041ee84 = 0x01b02b0c
0x0041ee74 = 0x00000020
0x0041ee68 = 0x00000000
0x0041ee50 = 0x00000000
0041f104 6ebd1b4c [GCFrame: 0041f104]
.load sos
已加载扩展C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll
!name2ee *!Test_Console.Struct1 //得到Struct1的方法表地址
PDB symbol for mscorwks.dll not loaded
Module: 6d5d1000 (mscorlib.dll)
--------------------------------------
Module: 00192c5c (Test_Console.exe)
Token: 0x02000012
MethodTable: 00193828
EEClass: 007a45b4
Name: Test_Console.Struct1
!clrstack -a //得到struct1实例的栈上地址
OS Thread Id: 0x1438 (5176)
ESP EIP
003eef0c 008f00c9 Test_Console.Class12.Main()
LOCALS:
0x003eef1c = 0x01c12b0c
003ef17c 6ebd1b4c [GCFrame: 003ef17c]
!dumpvc 00193828 0x003eef1c //查看值类型的layout
Name: Test_Console.Struct1
MethodTable 00193828
EEClass: 007a45b4
Size: 20(0x14) bytes
Fields:
MT Field Offset Type VT Attr Value Name
6d84340c 400001c a System.Byte 1 instance 1 a
6d83e910 400001d 8 System.Int16 1 instance 15 b
6d8408ec 400001e 0 System.String 0 instance 01c12b0c c
6d842b38 400001f 4 System.Int32 1 instance 32 d
在内存窗口中可以看到内存布局为:
0x003EEF1C 01c12b0c 00000020 0001000f
这里我要说明下使用dumpvc后会给出一个size,这里是20字节,比我们计算的结果多出8个字节,我的理解是因为引用类型有附加的8字节(syncblkindex + methodtableaddress)所以这里的size也加上了8.
C# Struct的内存布局的更多相关文章
- C++ 中类的内存布局
在许多笔试面试中都会涉及到sizeof 运算符的求值问题. 这类问题主要分四类: 基本数据类型,如int,bool,fload,long,long,int * 等,这一类比较简单,但要注意x86和x6 ...
- VS2010下如何查看类的内存布局
用VS2010查看类的内存布局,这里用两种方法 (1)MSVC有个隐藏的"/d1"开关,通过这个开关可以查看项目中类的内存布局情况. 修改项目属性,添加"/d1 repo ...
- [转]struct实例字段的内存布局(Layout)和大小(Size)
在C/C++中,struct类型中的成员的一旦声明,则实例中成员在内存中的布局(Layout)顺序就定下来了,即与成员声明的顺序相同,并且在默认情况下总是按照结构中占用空间最大的成员进行对齐(Alig ...
- 内存对齐与ANSI C中struct型数据的内存布局 【转】
转自:http://blog.chinaunix.net/uid-25909619-id-3032209.html 当在C中定义了一个结构类型时,它的大小是否等于各字段(field)大小之和?编译器将 ...
- 内存对齐与ANSI C中struct型数据的内存布局
当在C中定义了一个结构类型时,它的大小是否等于各字段(field)大小之和?编译器将如何在内存中放置这些字段?ANSI C对结构体的内存布局有什么要求?而我们的程序又能否依赖这种布局?这些问题或许对不 ...
- 浅析内存对齐与ANSI C中struct型数据的内存布局-内存对齐规则
这些问题或许对不少朋友来说还有点模糊,那么本文就试着探究它们背后的秘密. 首先,至少有一点可以肯定,那就是ANSI C保证结构体中各字段在内存中出现的位置是随它们的声明顺序依次递增的,并且第一个字段的 ...
- 图说C++对象模型:对象内存布局详解
0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看. 本文的结论都在VS2013上得到验证.不同的编译器在内存布局的细节上可能有 ...
- 根据内存布局定位的一个fastdfs坑
在使用fastdfs时,编写数据上传代码时,遇到一个坑.最终根据指针对应的内存布局定位到一个其client API的一个坑,值得记录一下.具体是在 tracker_connect_server() 这 ...
- C++ Data Member内存布局
如果一个类只定义了类名,没定义任何方法和字段,如class A{};那么class A的每个实例占用1个字节的内存,编译器会会在这个其实例中安插一个char,以保证每个A实例在内存中有唯一的地址,如A ...
随机推荐
- IIS支持net.tcp
绑定 高级设置 http和net.tcp用逗号分隔 //擦擦擦,见鬼了,下面的是tcp.net导致我找了好久,都找不出这个错误 //一定要注意,不要写错了. 否则会收到提示:找不到具有绑定 NetT ...
- 从tcp原理角度理解Broken pipe和Connection reset by peer的区别
从tcp原理角度理解Broken pipe和Connection reset by peer的区别 http://lovestblog.cn/blog/2014/05/20/tcp-broken-pi ...
- -_-#【Better Code】
i++ 与 ++i 的性能区别 if (true) { console.log('hi') } if (!false) { console.log('hi~') } true && c ...
- android studio class org.bouncycastle.asn1.asn1primitive overrides final method equals
好吧 上手as 又遇到一个问题: class org.bouncycastle.asn1.asn1primitive overrides final method equals... 项目运行的是后报 ...
- Ignatius and the Princess IV
Ignatius and the Princess IV Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32767 K ( ...
- Apache FileUpload详细介绍
Apache FileUpload组件 在最初的 http 协议中,没有上传文件方面的功能.RFC1867("Form-based File Upload in HTML".)为 ...
- linux关于bashrc与profile的区别(转)
转载自:http://www.cnblogs.com/hongzg1982/articles/2101792.html bashrc与profile的区别 要搞清bashrc与profile的区别,首 ...
- wxWidgets一个界面与数据分离的简单例子
/*************************************************************** * Name: MyApp.h * Purpose: Defines ...
- flushall()函数的用法
flushall()函数 如下所示的一个非常简单的程序. #include void main(void) { char cA,cB; printf("input cA and cB:\n& ...
- 从MSN上拔下来的全世界国家下拉框(附带SQL执行脚本)
<select> <option value="AL">阿尔巴尼亚</option> <option value="DZ&quo ...