探究C#中Class和Struct互相嵌套的内存问题

这篇具有很好参考价值的文章主要介绍了探究C#中Class和Struct互相嵌套的内存问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

内存分区

先回顾一下C#的内存种类

  1. 栈区:由编译器自动分配释放 ,存放值类型的对象本身,引用类型的引用地址(指针),静态区对象的引用地址(指针),常量区对象的引用地址(指针)等。其操作方式类似于数据结构中的栈。

  2. 堆区(托管堆):用于存放引用类型对象本身。在c#中由.net平台的垃圾回收机制(GC)管理。栈,堆都属于动态存储区,可以实现动态分配。

  3. 静态区及常量区:用于存放静态类,静态成员(静态变量,静态方法),常量的对象本身。由于存在栈内的引用地址都在程序运行开始最先入栈,因此静态区和常量区内的对象的生命周期会持续到程序运行结束时,届时静态区内和常量区内对象才会被释放和回收(编译器自动释放)。所以应限制使用静态类,静态成员(静态变量,静态方法),常量,否则程序负荷高。

  4. 代码区:存放函数体内的二进制代码。

内存分配

值类型分配在栈上,引用类型分配在堆上,这个概念一般都是比较清楚的。但是遇到下面的情况内存又是如何分配的呢?

Struct中嵌套Class对象

using System.Runtime.InteropServices;

namespace MyNamespace
{
    namespace MyNamespace
{
    public class B
    {
        public int x;
        public byte y;
    }

    public struct A
    {
        public byte x;
        public B b;
    }

    public class Test
    {
        static A a;
        public static void Main()
        {
            a = new A()
            {
                x = 1,
                b = new B() { x = 1, y = 1 },
            };

            System.Console.WriteLine(Marshal.SizeOf(a));
        }
    }
}

思考一下打印出来的值会是多少?

32位系统:
探究C#中Class和Struct互相嵌套的内存问题

64位:
探究C#中Class和Struct互相嵌套的内存问题

原因:

  1. 不同的编译器(x86、x64)对应的指针大小不一样。x86指针大小4个字节,x64指针大小为8个字节
  2. struct中存储Class,存储的是类的指针引用。整个Struct开辟在栈上,但是真正的类内存依旧是开辟在堆上。
  3. struct存在内存对齐的问题(提高访问速度)。内存对齐会向内存最大的那个对齐,即测试代码中,A.x会向(A.b的指针)大小对齐。

结论:Struct中嵌套Class引用对象,持有的是Class的引用指针。

Claas中嵌套Struct

using System.Runtime.InteropServices;

namespace MyNamespace
{
    public class B
    {
        public int x;
        public A y;
    }

    public struct A
    {
        public int x;
        public byte y;
    }

    public class Test
    {
        static B b;
        public static void Main()
        {
            b = new B()
            {
                x = 1,
                y = new A() { x = 1, y = 1 },
            };
        }
    }
}

通过对堆内存进行快照,思考一下32位下的内存大小
探究C#中Class和Struct互相嵌套的内存问题

出乎意料的内存大小!为什么会是这样的内存大小,我们先研究一下如果仅仅只有一个空对象,这个对象在内存中的大小是多少呢?我们通过查阅.Net官方文档看一下,一个对象是如何分配的:
探究C#中Class和Struct互相嵌套的内存问题

引用类型变量(如smallObj)以固定大小(4字节)存储在栈上,并指向在托管堆上分配的对象实例的地址。 smallObj的实例包含指向相应类型的MethodTable的TypeHandle(类型对象指针)和syncblk index(同步块索引,用来做线程同步的,这里就不详细讲了,大家可以去原文查看)。最后当一个类没有定义任何实例字段,它将产生4个字节的开销(用于进行属性字段的占用)。这样我们就可以算出32位下一个空对象的内存大小了:4(syncblk index)+ 4(TypeHandle)+ 4(Instance Fields)= 12个字节。同理在64位下将会是24个字节。


返回到上面的测试用例,这时候我们就明白为什么是这样的内存分配大小了。32位下:基础的8个字节 + 4字节(int)+ 4字节(Struct A.x)+ 4字节(Struct A.y,内存对齐) = 20个字节。64位下的32个字节留给大家思考是怎么样一个组成的呢?

总结

  • Struct内部持有的是Class的指针
  • Class内部持有的也是Struct的指针,但是这些都是开辟在堆上的
  • Class需要分配syncblk index和TypeHandle,用来进行同步索引和类型查询,在考虑Class的内存开销的时候需要考虑进去。
  • 内存对齐会影响内存大小

探究C#中Class和Struct互相嵌套的内存问题文章来源地址https://www.toymoban.com/news/detail-478136.html

到了这里,关于探究C#中Class和Struct互相嵌套的内存问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++的结构体(struct)和类(class)对比

    在C++中,结构体(struct)和类(class)都是用户自定义的数据类型,用于封装数据和方法。结构体通常用于定义一些简单的数据结构,而类则更多的用于面向对象的编程。 两者的不同之处如下: 结构体 (struct)是一种简单的数据集合,它可以包含不同类型的成员变量,但默

    2024年02月15日
    浏览(48)
  • c与c++中struct的主要区别和c++中的struct与class的主要区别

    c中的struct不可以含有成员函数,而c++中的struct可以。 C语言 c中struct 是一种用于组合多个不同数据类型的数据成员的方式。struct 声明中的成员默认是公共的,并且不支持成员函数、访问控制和继承等概念。C中的struct通常被用于将多个相关数据组合在一起,但没有类的其他功

    2024年02月11日
    浏览(50)
  • C++面试八股文:struct、class和union有哪些区别?

    某日小二参加XXX科技公司的C++工程师开发岗位5面: 面试官:struct和class有什么区别? 小二:在C++中,struct和class的唯一区别是默认的访问控制。struct默认的成员是public的,而class的默认成员是private的。 面试官:struct、class和union有哪些区别? 小二:union和struct、class在内存布

    2024年02月07日
    浏览(54)
  • 基于WebRTC构建的程序因虚拟内存不足导致闪退问题的排查以及解决办法的探究

    目录 1、WebRTC简介 2、问题现象描述 3、将Windbg附加到目标进程上分析

    2024年02月08日
    浏览(52)
  • 【C++】类和对象 - 封装 - 属性和行为,访问权限,class 和 struct区别,成员属性私有化

    No. Contents 1 【C++】基础知识 - HelloWorld,注释,变量,常量,,标识符 2 【C++】数据类型 - 整型,sizeof,实型,字符型,转义字符,字符串类型,布尔类型,数据的输入 3 【C++】运算符 - 算术运算符,赋值运算符,比较运算符,逻辑运算符 4 【C++】程序流程结构 - 循序结

    2024年02月07日
    浏览(49)
  • C#: 结构体 struct 应用笔记

    说明:记录 在 C# 中的一些结构体相关的应用         在下面的示例中,在struct中定义了一个固定长度为 8 的 byte 数组 data 。通过使用 MarshalAsAttribute 的 UnmanagedType.ByValArray 参数,指定了数组的类型为值类型数组,并使用 SizeConst 字段指定了数组的大小为 8。请注意,使用固

    2024年01月17日
    浏览(50)
  • C# --- Struct and Record

    struct是一种数据类型, 和class非常类似, 主要有以下的不同 struct是value type, class是reference type 因为是value type所以strcut不是必须储存在heap上 struct不能等于null, The default value for a struct is an empty instance, with all fields empty (set to their default values). struct 支持值比对, 也就是可以直接用等于

    2024年02月12日
    浏览(39)
  • [游戏开发][Unity] Xlua与C#互相调用规则

    静态方法无需获取类对象,获取到类直接执行 例1: 例2 调用非静态方法一定要获取到具体的C#类对象!!! 例1:获取单例对象并调用非静态方法,Singleton是单例的一种写法,网上源码很多 下面是Lua调用C#的代码,我这是模拟Xlua的工程,以类的方式实现交互 看Log日志发现:

    2024年02月07日
    浏览(77)
  • Unity Native Plugin C#和C++互相调用

    官方链接 1.DLL的方式: C++代码:编译成DLL,导入Unity C#代码: 2.还有一种是C++源码作为插件,只支持il2cpp。 C++代码:直接放到Unity的Assets目录下 C#源文件:区别只在导入时不写具体的文件名,写:__Internal即可,因为用IL2CPP 后端的方式,会把C++源文件放到工程内部一块编译。

    2024年02月12日
    浏览(43)
  • c#向c++(opencv)实现双向图像数据传递,以及内存空间申请与释放问题

    c++与c#之间对应的数据关系: https://blog.csdn.net/qq_44544908/article/details/128784250 c++转换到c#的辅助工具(推荐,可以自动按照输入的c++代码函数或结构体转换为c#代码段): https://codeload.github.com/jaredpar/pinvoke-interop-assistant/zip/refs/heads/master 数据转换的基本依据: 一个数据有两个特征:

    2024年02月12日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包