当前位置: 首页 > news >正文

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

 

  • 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

相关文章:

  • 学习python的网址
  • 45 个非常有用的 Oracle 查询语句
  • Oracle 创建表空间一边串过程
  • 解读《TCP/IP详解》(卷1):03章:IP(网际协议)
  • LeetCode: Reverse Linked List II
  • oracle临时表(JDBC应用)
  • 笛卡尔叶形曲线所围图形的面积
  • app后端设计(7)-- 项目管理
  • Linq语言性能比较
  • Enabling Process Accounting on Linux HOWTO
  • IntelliJ IDEA 使用GitHub代码仓库保存自己的代码
  • 【转】Picasso – Android系统的图片下载和缓存类库
  • codeforces C. Cows and Sequence 解题报告
  • hdu1231(最大连续子序列)
  • Android Studio Gradle project refresh failed No such property classpath for class
  • “大数据应用场景”之隔壁老王(连载四)
  • C学习-枚举(九)
  • JavaScript类型识别
  • Netty+SpringBoot+FastDFS+Html5实现聊天App(六)
  • swift基础之_对象 实例方法 对象方法。
  • 精彩代码 vue.js
  • 力扣(LeetCode)21
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • 携程小程序初体验
  • 用Visual Studio开发以太坊智能合约
  • FaaS 的简单实践
  • ​【已解决】npm install​卡主不动的情况
  • ​ArcGIS Pro 如何批量删除字段
  • #控制台大学课堂点名问题_课堂随机点名
  • (1)安装hadoop之虚拟机准备(配置IP与主机名)
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (WSI分类)WSI分类文献小综述 2024
  • (ZT)薛涌:谈贫说富
  • (办公)springboot配置aop处理请求.
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (算法)N皇后问题
  • (算法)Travel Information Center
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • .Net下C#针对Excel开发控件汇总(ClosedXML,EPPlus,NPOI)
  • /etc/fstab和/etc/mtab的区别
  • @31省区市高考时间表来了,祝考试成功
  • @SpringBootApplication 包含的三个注解及其含义
  • [ vulhub漏洞复现篇 ] struts2远程代码执行漏洞 S2-005 (CVE-2010-1870)
  • [ 环境搭建篇 ] 安装 java 环境并配置环境变量(附 JDK1.8 安装包)
  • [ 数据结构 - C++] AVL树原理及实现
  • [ 云计算 | AWS 实践 ] Java 如何重命名 Amazon S3 中的文件和文件夹
  • [17]JAVAEE-HTTP协议
  • [2019.2.28]BZOJ4033 [HAOI2015]树上染色
  • [AIGC] Spring Interceptor 拦截器详解
  • [BeginCTF]真龙之力
  • [C puzzle book] types
  • [C++]C++基础知识概述
  • [C++]类和对象【上篇】
  • [EFI]MSI GF63 Thin 9SCXR电脑 Hackintosh 黑苹果efi引导文件