C# C语言中一个小类的内存优化#

C# C语言中一个小类的内存优化#,c#,memory,optimization,C#,Memory,Optimization,我有一段代码,它将字符串的大型矩阵转换为MyClass的大型矩阵MyClass是我编写的一个小类,它存储关于每个字符串的一些信息,如下所示: class MyClass { public MyEnum Class { get; private set; } public int A { get; private set; } public int B { get; private set; } public int C { get; private set; }

我有一段代码,它将字符串的大型矩阵转换为
MyClass
的大型矩阵
MyClass
是我编写的一个小类,它存储关于每个字符串的一些信息,如下所示:

class MyClass
{
    public MyEnum Class { get; private set; }

    public int A { get; private set; }
    public int B { get; private set; }
    public int C { get; private set; }
    public int D { get; private set; }
}
[StructLayout(LayoutKind.Sequential, Pack=1)]
struct MyStruct
{
    public readonly MyEnum Class;
    public readonly int A;
    public readonly int B;
    public readonly int C;
    public readonly int D;

    public MyStruct(MyEnum cls, int a, int b, int c, int d)
    {
        Class = cls;
        A = a;
        B = b;
        C = c;
        D = d;
    }
}
目前,该软件能够处理5-20列乘以100万行的矩阵,但我想将行数增加到接近1000万行。我不相信我能做多少来减少字符串矩阵的占用空间,但我想减少
MyClass
的内存占用空间

我可以使用
short
作为列
A
的类型,
byte
作为
B
C
D
的类型,尽管这需要对代码进行相当大的重构

我的问题,或者更确切地说是问题:

  • 使用
    short
    byte
    重构代码是否值得
  • 我是否也应该将
    MyEnum
    重构为
    byte
    类型
  • 我还能做些什么来提高课堂效率吗
  • 非常感谢您的时间


    编辑:多一点上下文-出于分析目的,
    MyClass
    的矩阵是从字符串矩阵创建的。字符串矩阵是通过普通的网络连接从文本文件中提取出来的,因此将任务分割成较小的数据块并不理想。

    就缩小类而言,您使用其他数据类型的建议是正确的。 这将减少分配的整个内存量。 就内存中的数据表示而言,您似乎创建了某种hana,是吗? 如果是这种情况,还有其他优化,主要称为对集合的引用,也就是说,您不是在每个列中存储实际值,而是在存储对属于具有唯一条目的字典的其他值的引用。 此外,您必须以另一种方式对齐数据。不要认为是行导向的,而是在内存中(或至少在大脑中)切换到列导向的数据表示

    SAP hana使用这些技术将大量数据保存在内存中,而不是硬盘上。

    为16位

    是32位

    您可以设置枚举的大小,而无需进行所述的任何实际工作

    这意味着你可以将班级人数减少一半。
    如果这对于工作量来说已经足够了-这取决于您

    到目前为止,假设您的所有属性都是由实例变量实现的,并且您运行在64位机器上,那么MyClass的实例是4B*4+8B=24B。 此外,由于您使用的是一个类(引用类型),MyClass的矩阵每个单元格的权重将进一步增加到8B。这意味着每个单元使用32B。然后,MyClass的10Mx20矩阵使用大约6.4GB(对于这些大小,您必须使用64位二进制文件),这可能不止这些,因为我忽略了内存对齐要求

    如果从类切换到结构(值类型),矩阵将直接存储MyClass实例,而不是指向MyClass实例的指针。因此,每个实例将节省8B。 现在,内存使用率下降到4.8GB

    如果使用1个短字节和3个字节进一步优化实例变量,并将枚举转换为字节,则每个实例将仅使用6B。因此,总内存使用量将降至1.2GB

    无论如何,这将不止于此,因为托管环境在每个对象中存储一些其他元数据,并且因为内存对齐需要填充对象以加快访问时间

    PS:您实际上不需要更改属性的返回类型。您可以封装类型更改,并在MyClass的实现中执行强制转换,如:

    struct MyClass
    {
      private short a; //Also consider ushort, if you need it
      //...
    
      public int A
      {
        get { return a; //Automatic promotion }
        private set
        {
          a = (short) value;
          System.Diagnostics.Debug.Assert(a == value, "Integer overflow");
        }
      }
    
      //...
    }
    

    这样,优化将对使用MyClass的代码透明。

    如果使用类,可以通过创建n个子类
    MyClass
    ,为
    MyEnum
    的每个值创建一个子类(如果
    MyEnum
    具有离散数量的值),然后删除
    MyEnum
    来获得收益


    只有当
    MyClass
    显然是一个类时,这才有效。

    可以做很多事情来减小字符串矩阵的大小,当然这取决于字符串包含的内容。如果有许多重复的字符串,可以使用或

    如果您的字符串不重复,但通常是ASCII或其他一些单字节编码(或使用大多数单字节字符的UTF-8),则可以通过以下方式节省大量内存。请参阅以获取介绍

    对于您的
    MyClass
    ,您需要为每个实例支付16字节的分配开销,这几乎与数据本身所占用的空间相同。如果成员都是不可变的,我建议将其设置为
    struct
    。它们似乎在公开场合是不可变的。你私下做什么,我不知道。但是像这样的事情:

    class MyClass
    {
        public MyEnum Class { get; private set; }
    
        public int A { get; private set; }
        public int B { get; private set; }
        public int C { get; private set; }
        public int D { get; private set; }
    }
    
    [StructLayout(LayoutKind.Sequential, Pack=1)]
    struct MyStruct
    {
        public readonly MyEnum Class;
        public readonly int A;
        public readonly int B;
        public readonly int C;
        public readonly int D;
    
        public MyStruct(MyEnum cls, int a, int b, int c, int d)
        {
            Class = cls;
            A = a;
            B = b;
            C = c;
            D = d;
        }
    }
    
    结果每个实例总共有20个字节,没有每个实例的分配开销。因此,1000万行乘20列将是(10M*20*20),或大约4G字节。在.NET 4.5中,您可以使用配置设置创建一个如此大的数组

    但是,请注意,您可能会遇到性能问题。考虑这个代码:

    MyStruct m = MyArray[x,y];
    // now access fields of m
    
    使用struct,在
    MyArray[x,y]
    处创建项的副本。这意味着复制20个字节。这还意味着,如果修改
    m.A
    ,该更改将不会反映在数组中。您要么将其复制回来(即
    MyArray[x,y]=m;
    ),要么完全放弃中间变量并写入
    MyArray[x,y].A=5

    当然,如果您的结构是不可变的,那么就不会有复制回的问题


    使用C#处理内存中的大量项目是可能的,但您必须对如何处理这些项目具有创造性。我发现以这种方式使用结构非常有效,特别是当它们是不可变的时。

    您真的需要同时将所有这些数据存储在内存中吗?我必须承认