博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c#对象的内存结构(学习笔记)
阅读量:5011 次
发布时间:2019-06-12

本文共 2902 字,大约阅读时间需要 9 分钟。

 

  • 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对象里面的字段内存分布为

那么有继承的时候又是怎样的呢?按上述操作便可以总结出规律。哈哈

 

 

转载于:https://www.cnblogs.com/tobecabbage/p/3528064.html

你可能感兴趣的文章
虚函数的效率问题
查看>>
POJ 1860 Currency Exchange(SPFA 判断有无“正”环)
查看>>
广告地址屏蔽
查看>>
收缩SqlServer数据库日记方法
查看>>
每日英语:15 places to find inspiration
查看>>
学习方法--提问
查看>>
【转】每天一个linux命令(3):pwd命令
查看>>
merge-two-sorted-lists
查看>>
MySQL(3)
查看>>
poj1061——扩展gcd水题
查看>>
UVa400.Unix ls
查看>>
POJ 2299 Ultra-QuickSort 归并排序、二叉排序树,求逆序数
查看>>
Educational Codeforces Round 60 (Rated for Div. 2) C. Magic Ship
查看>>
Windows 2008 R2系统开机时如何不让Windows进行磁盘检测?
查看>>
WP7应用开发笔记(18) 本地化与多语言
查看>>
解决 .so文件64与32不兼容问题
查看>>
归并排序法
查看>>
【剑指offer】面试题26:复杂链表的复制
查看>>
spark开发生成EXE
查看>>
Vue 全家桶介绍
查看>>