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#处理内存中的大量项目是可能的,但您必须对如何处理这些项目具有创造性。我发现以这种方式使用结构非常有效,特别是当它们是不可变的时。您真的需要同时将所有这些数据存储在内存中吗?我必须承认