优化Dictionary键的内存要求

时间:2011-02-26 13:02:46

标签: c# .net collections

除了我有一个(大)字典实例的集合。该字典中的关键值始终是10个已知字符串之一。

如果集合包含1000000个条目,那个字符串键值是否会占用每个实例和键的内存?有没有什么好方法来优化这样的案例,也许是使用字符串实习?

另一种方法是使用一个简短的密钥替换密钥并在字符串和短文之间进行转换,但语法变得有点混乱......

5 个答案:

答案 0 :(得分:1)

通常不是 - 它们存储为单个不可变变量。字符串可以是interned,这有助于节省内存。

但这取决于。如果每次构造字符串(例如连接),它们将不会被实现。将它们定义为常量可确保它们被实习。

您可以使用object.ReferenceEquals()检查内存中的两个字符串是否相同。

答案 1 :(得分:1)

String是引用类型。该字典包含对实际字符串对象的引用,32位操作系统上的4个字节。将相同的字符串添加到多个字典只会产生一个字符串副本。

你已经得到了你想要的东西。

答案 2 :(得分:0)

我认为为了节省空间或优化它,我们可以做其中之一。

  • 为每个项目名称(字符串)创建10个不同的List<T> s的int。然后在检索时在所有10个列表中搜索项目。

  • 或者创建像这样Dictonary<List<int>,string>的列表字典,并为每个项目名称(字符串)存储每个键(在相应的列表中)。它与上面几乎相同,但允许你以后添加更多项目。

而且我相信我们仍然会有更好的表现

(但我希望其他人对我的假设发表评论)

此外,如果您有大约1,00,000条记录,则最好将其存储在数据库中,并且有两个表,其中一个包含字符串,一个ID用于Item name,另一个包含key和外键到Item ID。

答案 3 :(得分:0)

常量字符串被实现(因此string str = "hello";被实现)。其他字符串通常不是。您可以使用String.Intern静态方法强制执行字符串,但请务必阅读http://msdn.microsoft.com/en-us/library/system.string.intern.aspx上的副作用。请记住,如果您有一个const hello字符串和一个动态构建的hello字符串,则只会阻止第一个字符串。有时你可以通过实习经常使用的字符串获得一点记忆。 在您的情况下,如果您只使用少量已经记忆在另一个集合中的字符串并复制这些字符串(var str2 = str1),那么您不会复制该字符串,只会创建另一个引用。但是如果您获得操作旧字符串(var str2 = ("Z" + str1).Substring(1))的新字符串,那么您实际上是在创建一个新字符串而不是引用旧字符串。

答案 4 :(得分:0)

正如其他人所说,这取决于你如何将字符串放入列表中。一些例子应该有所帮助。

想象一下,你有一个包含1,000行的文本文件,都是一样的。也就是说,一个文件重复“hello”1000次:

hello
hello
hello
...

如果你编写一个程序来将该文件读成List<string>天真的方式,那么将有1,000个不同的字符串实例。那就是:

var myList = new List<string>();
var reader = new StreamReader("filename");
string s;
while ((s = reader.ReadLine()) != null)
{
    myList.Add(s);  // each string is a unique instance
}

如果关注内存,那么您要做的是维护一个包含字符串键和字符串值的查找表。它是字符串到单个值的映射。因此,当您使用重复的字符串时,您将获得对第一个实例的引用。

var KeyLookup = new Dictionary<string, string>();
string AddString(string key)
{
    string value;
    if (!KeyLookup.TryGetValue(key, out value))
    {
        value = key;
        KeyLookup.Add(key, value);
    }
    return value;
}

然后当你阅读文件时:

while ((s = reader.ReadLine()) != null)
{
    myList.Add(AddString(s));  // duplicate strings use the same instance
}

在这种情况下,程序中只有一个字符串"hello"的实例。

您可以使用列表中的键执行类似操作。为您的密钥创建一个查找表,并确保无论何时向列表中添加密钥,都要从查找表中添加值而不是密钥本身。

正如其他人所指出的那样,如果你的已知密钥已经是常量,并且在将它们添加到列表时总是使用常量值,那么字符串已经被实习并且上面不是必需的。