C#继承场景下的对象内存分配问题
C#继承场景下的对象内存分配详解
嘿,这个问题问到点子上了——很多刚摸C#继承的开发者都会在这一块绕晕,我给你掰扯得明明白白~
先敲个核心结论:当你执行new Derived()的时候,堆上只会创建一个单一、完整的Derived对象,它包含了基类Base的所有基础结构(哪怕你的Base是空类),再加上Derived自己的成员——根本不存在“基对象”和“派生对象”相互独立或者谁包含谁的情况。
下面分别拆解两种引用场景:
1. Derived d = new Derived();
- 堆内存:分配一块连续的内存区域,里面是完整的
Derived实例。哪怕你的Base是空类,这块内存也会包含.NET对象必备的对象头(同步块索引、类型指针等基础信息),再加上Derived自定义的所有成员(如果有的话)。 - 栈内存:
d是一个引用变量,它存储的是堆上那个Derived对象的内存地址。因为d的类型是Derived,所以你可以直接通过它访问Derived的所有成员,以及继承自Base的成员。
2. Base b = new Derived();
- 堆内存:和上面完全一模一样!还是那个完整的
Derived对象,内存分配没有任何区别——不会因为引用类型是Base就只分配Base的部分。 - 栈内存:
b是一个Base类型的引用变量,它同样存储的是堆上那个Derived对象的地址。只不过编译器会根据b的类型做限制,你只能通过它访问Base中定义的成员(除非你显式做类型转换),但堆里的对象本身从头到尾都是完整的Derived实例。
额外补充:空基类为啥也占空间?
哪怕你的Base没有任何自定义成员,每个.NET对象在堆上都会有固定的对象头开销,用来存储对象的类型信息、同步状态等核心数据。所以new Base()也会分配一定的内存,而Derived对象就是在这个基础上,叠加自己的成员数据。
打个形象的比方:把Derived对象看成一个完整的快递盒,Base的部分是盒子的硬纸板框架,Derived的成员是盒子里装的东西——整个盒子是一个不可分割的整体,不存在两个分开的盒子。引用类型只是贴在盒子上的标签,标签的类型决定了你能直接打开盒子的哪个隔层,但盒子本身的内容从来没变过。
内容的提问来源于stack exchange,提问作者sandeep addala
相关产品推荐
相关产品推荐

