C# 内存知识

C# 内存知识

C# 是一种编程语言, 通过堆C#源码的编译后产出中间语言(IL)。然后CLR(公共语言运行时)会加载这些IL并执行。所以C#是一种托管语言,它的垃圾回收机制(GC)是由 CLR 负责的,加之C# 语言并没有指针,所以我们在使用过程中极少考虑到内存使用状况以及项目在运行过程中是如何进行内存管理的。但是,C# 只是在内存管理方面对程序员隐藏了,并不代表它不涉及这些东西西,甚至其内部管理或许比自己管理更复杂。

C# 对象分类

C# 中的对象分为值类型(value type)和引用类型(reference type)。 详细信息参考C#的两种类据类型:值类型和引用类型.

对于值类型,变量直接存储其数据(栈上),而对于引用类型,变量仅存储地址(栈上),对应的数据可以在该地址(堆上)找到(如果值类型在引用类型中声明为字段,他们就内联存储在堆中)。

C# 内存机制 - 基础篇

C# 结构体的内存分配

在与非托管代码进行互操作时,有时会需要传递结构体参数。 因为两者之间存在内存分配上的差异,而解决这个差异必须知道C#中的结构体内存分配与大小。先简单看下相关的代码如下:

// 所有结构体均使用默认的特性
// StructLayoutAttribute 类使用户可以控制类或结构的数据字段的物理布局。
StructLayoutAttribute(Value = LayoutKind.Sequential, Pack = 8)

// 结构体实际大小计算使用
Marshal.SizeOf(typeof(StructName))

然后看下例子,占用的内存大小也标注出来了:

struct s1 // 32字节
{
    int x;    // 4 :0-3
    double b; // 8 :8-16 (由于剩余的不足8字节,所以这里的空间浪费了)
    double b; // 8 :17-24
    byte a;   // 1 :25 (根据字节对齐原则,后面7个字节留空)
}
struct s2 // 24字节
{
    byte a;   // 1 :0
    int x;    // 4 :1-4
    double b; // 8 :8-16 (浪费三个字节,从下一个对齐位置开始)
    double c; // 8 :17-24
}

可以看出存在字节对齐的问题。在连续分配的过程中,不足8字节的对齐到8字节,如果剩下不足以存放下一个变量,则补齐到8字节,下一个8字节开始保存。
如果能确定不会传递给dll,而仅仅是由托管环境使用,则可以不需要StructLayout(默认auto),这可能会提高内存利用率。因为.net会对托管对象的布局进行调整,例如例子中一样,调整顺序后内存利用率得到了提升。

猜你喜欢

转载自blog.csdn.net/qq_36433883/article/details/126702194