您的位置:首页 > 编程语言 > C#

c#对象的内存结构(学习笔记)

2014-01-21 11:24 316 查看
C#里用指针

指针其实就是地址

定义一个 int*类型指针变量pointNum。





c#是安全性语言,不允许有指针,所以只能将指针放置在不安全的上下文中





解决办法:右击项目,选择“属性”,在属性对话框里,选择“生成”选项卡。将允许不安全代码单选框勾选上



使用地址的代码

class Program
{
static void Main(string[] args)
{
int num = 10;
unsafe {
int  * pointNum;//声明一个用来存储int类型数据的地址变量
pointNum = #//用&取址地址运算符得到num的变量的地址
//可以使用pointNum表示num的地址进行访问
//所以 *运算符号表示取值运算符,*(地址数)就是地址数表示的位置的数据 (该说法是类比,不严格)
//  *pointNum=110;
}
}
}


构造方法的执行过程(对象的创建过程)

1.给对象分配内存时,将字段分配在堆空间里,方法(属性,索引,事件)都存在线性栈中,每个对象在堆空间内存里首尾各4个字节(基于32进制的),分别是描述对象类型的内存(类似元数据,但是不是元数据),和同步索引块。它们用来

2.计算机扫描内存时是有一个对齐的概念,32位的计算机扫描单位为4个字节,64位的计算机扫描的单位是4个字节。所以计算机在分配内存时,遵守内存对齐的规范。便于计算机查询地址。比如 字段有char类型 long类型 int类型,先给long类型的字段分配内存,然后再是int类型字段的内存,最后才是char类型

对象的内存大小满足公式(此为蒋坤老师经过大量数据的统计而得到的公式)

所有字段所占内存的总和+首尾各4个字节+常数=最小的4的倍数

其中,常数只是为了满足最小的4的倍数,而分配的。

class MyClass1
{
public int num = 3;
}

class Program
{
static void Main(string[] args)
{
MyClass1 c1 = new MyClass1();
MyClass1 c2 = new MyClass1();
MyClass1 c3= new MyClass1();
MyClass1 c4 = new MyClass1();
}
}




通过调试,我们发现每个对象的内存地址相差12个字节,我们可以看是否匹配内存公式:

num字段占4个字节+首尾各各四个字节(8个字节)+常数=0

所以常数应该为0个字节,这里不需要常数。

所以我们可以根据公式算出c1的num字段的内存地址为:0x01b5128

通过查看内存地址 我们验证我们的公式是否正确(需要注意的是,我们再次调试的时候,对象的地址已经改变,所以根据新改变的地址,即新的c1的地址+4=c1的num地址)



调试后发现,我们公式推出的C1的num字段地址是正确的。

另一中验证方法,取地址运算,即扫描地址区间的个数

class MyClass1
{
public int num = 3;
}

class Program
{
static void Main(string[] args)
{
MyClass1 c1 = new MyClass1();
MyClass1 c2 = new MyClass1();
MyClass1 c3= new MyClass1();
MyClass1 c4 = new MyClass1();

unsafe
{
fixed (int* pointNum = &c1.num)
{
//将这个变量固定起来,以使它不被垃圾回收,这样它的地址就固定下来。
Console.WriteLine(*(pointNum + 3));//将c1.num地址移动三个
// 中间越过一个c1对象的尾部地址(4个字节)c2的首部地址(4个字节)
// 就到了c2.Num的内存区,所以显示结果为3
}
}
Console.ReadKey();
}
}


对象内存结构图解



对象字段内存分布的排布

class MyClass12
{
public long l = 20;
public byte b = 0;
public char c = 'a';
public int num = 3;

}


按照我们一般的思维,各字段内存的排布为:



此图的排布是错误的。我们先按公式计算 首字节4个+long类型字段8个字节+byte类型1个字节+char类型2个字节+int类型4个字节+尾部字节4个=23, 所以需要加一个1个字节常量总共凑足最小4的倍数24。所以该类的每个对象占24个字节

class Program
{
static void Main(string[] args)
{
MyClass2 c1 = new MyClass2();
MyClass2 c2 = new MyClass2();
MyClass2 c3 = new MyClass2();
MyClass2 c4 = new MyClass2();
}
}


调试,四个对象的地址为



通过计算,发现每个对象的地址相差确实为24。

定义一个指针变量指向c1.Num,然后调试,在即时窗口中逐步将指针所指向的地址+1,知道加到24为止(也就是见c1对象占的所有内存遍历一次),查看地址里存储的数据,最后发现c1对象里面的字段内存分布为



那么有继承的时候又是怎样的呢?按上述操作便可以总结出规律。哈哈
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: