减少类似对象的内存

减少类似对象的内存

问题描述:

我正在寻找减少类似集合对象的表的内存消耗。减少类似对象的内存

给定一个类结构类似

Class Cell 
{ 
    public property int Data; 
    public property string Format; 
} 

Class Table 
{ 
    public property Dictionary<Position, Cell> Cells; 
} 

当有大量的细胞的细胞类的数据属性可以是可变的,但格式属性可被重复多次,例如标题单元可能具有用于标题的空格式字符串,并且数据单元可能都是“0.00”。

一个想法是像下面

Class Cell 
{ 
    public property int Data; 
    public property int FormatId; 
} 
Class Table 
{ 
    public property Dictionary<Position, Cell> Cells; 
    private property Dictionary<Position, string> Formats; 

    public string GetCellFormat(Position); 
} 

这对字符串但是FormatId整数值仍然会被重复多次将节省内存。

有没有比这更好的实现?我已经看过flyweight模式,但我不确定它是否与此匹配。

我正在考虑的一个更复杂的实现是从Cell类中删除Format属性,而将格式存储在将相邻单元格分组在一起的字典
可能有2项这样
<item rowFrom=1 rowTo=1 format="" />
<item romFrom=2 rowTo=1000 format="0.00" />

对于字符串,你也许可以看看实习;无论是内置的内部人员还是(最好是)定制的内部人员 - 基本上都是Dictionary<string,string>。这意味着每个相同的字符串使用相同的参考 - 并且可以收集重复项。

不要对int进行任何操作;那已经是最佳了。

例如:

using System; 
using System.Collections.Generic; 
class StringInterner { 
    private readonly Dictionary<string, string> lookup 
     = new Dictionary<string, string>(); 
    public string this[string value] { 
     get { 
      if(value == null) return null; 
      if(value == "") return string.Empty; 
      string result; 
      lock (lookup) { // remove if not needed to be thread-safe  
       if (!lookup.TryGetValue(value, out result)) { 
        lookup.Add(value, value); 
        result = value; 
       } 
      } 
      return result; 
     } 
    } 
    public void Clear() { 
     lock (lookup) { lookup.Clear(); } 
    } 
} 
static class Program { 
    static void Main() { 
     // this line is to defeat the inbuilt compiler interner 
     char[] test = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' }; 

     string a = new string(test), b = new string(test); 
     Console.WriteLine(ReferenceEquals(a, b)); // false 
     StringInterner cache = new StringInterner(); 
     string c = cache[a], d = cache[b]; 
     Console.WriteLine(ReferenceEquals(c, d)); // true 
    } 
} 

如果需要,您可以借此进一步与WeakReference

请注意,您的不需要更改您的设计 - 您只需更改填充对象以使用interner/cache的代码。

+0

+1尼斯例:) – 2009-11-13 06:42:30

+0

谢谢。我想我需要确定CLR是否已经为我做了这个。 – 2009-11-13 06:57:07

+0

该文档指定分配给CLR实例字符串的内存在CLR本身终止之前不可能被释放。这就是为什么你更喜欢定制的内部人员? – 2009-11-13 07:05:33

你真的确定这是否实际上是一个问题? CLR为你做了很多string interning,所以它可能(取决于CLR版本以及你的代码是如何编译的)你没有使用尽可能多的内存。

我强烈建议您在更改设计之前验证您对内存使用情况的怀疑。

+0

谢谢,我不知道。开始的例子是对已经存在的设计进行简化,这种设计占用了大量的内存,我假设了许多字符串要贡献。很难准确地确定内存的位置...... – 2009-11-13 06:53:29

正如其他人所说的,你首先要在改变你的设计之前看看这是否是一个问题。如果这是一个问题和/或你处理大量稀疏数据,那么稀疏数据结构可能更适用于问题。稍后我会发布一个非常简单的朴素实现(因为我目前无法做到),但是二维稀疏矩阵可以满足您的要求。

这个概念是为给定单元格范围存储单个格式(字符串或类),例如, 1-1000。为了从中受益,您必须进行一些设计更改......格式属性将需要从单元类中删除。相反,格式应该在表格类中注册,或者最好与其他类一起注册。例如,

public class CellFormats 
{ .... 
public void Register(int start, int finish, string format); 
} 

单元格格式类将包含稀疏矩阵,它将包含范围的格式。

Table类将使用CellFormats类。相反,有一个名为GetCellFormat方法,它必须具有以下签名

void ApplyCellFormat(Position cellPosition) 

这将检索来自CellFormats类(稀疏矩阵)单元格格式的方法,并将其应用到单元。

如果数据很常见并应用于大范围,此技术可以显着减少内存使用量。但正如我已经说过的,您需要确保这是问题的原因,然后才能通过添加这样的代码来使设计更复杂。