对象的内存结构(第五天培训内容)

 隐藏基类,重写基类,里氏转换等,抽象类内容略(前面博客已经有)

  • C#里用指针

指针其实就是地址

定义一个指针变量 int  *pointNum; *pointNum表示一个数字,pointNum表示内存地址

对象的内存结构(第五天培训内容)

对象的内存结构(第五天培训内容)

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

对象的内存结构(第五天培训内容)

对象的内存结构(第五天培训内容)

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

对象的内存结构(第五天培训内容)

使用地址的代码

对象的内存结构(第五天培训内容)
 class Program
    {
        static void Main(string[] args)
        {
            int num = 10;
            unsafe { 
            int  * pointNum;//声明一个用来存储int类型数据的地址变量
            pointNum = #//取地址运算符
                //可以使用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对象里面的字段内存分布为

对象的内存结构(第五天培训内容)

那么有继承的时候又是怎样,是傅雷

对象的内存结构(第五天培训内容)

上一篇:linux C守护进程编写


下一篇:是否缺少对 Microsoft.CSharp.dll 和 System.Core.dll 的引用?