情况:
在64x .NET版本中,我在Hashset中存储了大约5000万个字符串,而我的RAM从1.5Gb到7.5Gb。
2个问题:
查看字符串占用的6 Gb(7.5-1.5)RAM ...如果我说明的话,我是正确的:
Hashset对象大小= 8个字节*字符串数...其余最多6GB是保存在RAM中的实际字符串?
- 醇>
如果是,如果我将它保存在数据库中并使用Hibernate 示例(使用相同的RAM)我将在hashset中存储更多字符串 对象,但我需要考虑R / W数据库开销?
答案 0 :(得分:1)
不完全。对象的簿记比指针的大小要多一些。对象标题大约介于12-24个字节之间(我不确定它是64位上的 - 它是已定义的,但我现在没有时间搜索确切的值:))。字符串的长度是另外4-8个字节。缓存哈希的另外4个字节。每个字符至少两个字节。鉴于5000万个对象中的内存大小为6 GiB,平均每个对象大约需要128个字节。这意味着每个字符串在46-54个字符之间(包括一个双字节的空终止符)。我也很可能忘记其他开销来源。
散列集开销也将大于引用,但可能还不够重要。
为什么不运行内存探查器而不是在互联网上询问?它将向您展示一个很好的分配树,它可以确保(在您的特定配置上),而不是猜谜游戏。
至于其他解决方案,如果你需要内存中的东西,你可以获得的空间不是很多。也许,如果你的数据全部是ASCII,你可以避免使用Unicode。除非你的字符串很短,否则这是唯一会产生明显差异的东西。但我们真的无法分辨 - 我们不知道您的数据是由什么构成的。也许内存中的压缩字符串会很好用吗?我们无法知道 - 你需要自己测试一下。
修改强>
由于您要存储的数据只是几个数字,因此string
会不必要地浪费内存和性能。你可以做任何没有间接的事情,只使用价值类型。
现在,如果您熟悉不安全的代码,固定缓冲区可以使这非常简单易用:
public unsafe struct SevenNumbers
{
public fixed ushort Numbers[7];
}
(不要忘记添加GetHashCode
和Equals
覆盖)
确保使用通用哈希集 - 如果需要将结构转换为object
,则会失去使用值类型的所有好处,并且您将为引用,间接,对象头付费......不必要的浪费。
不安全的代码通常用于这样的优化,但是如果你不熟悉/不熟悉不安全的代码,你可以用更多的代码做同样的事情。要么您必须将这些数字作为单独的字段(Number1
,Number2
,...)来访问,要么您必须使用自定义索引器来假装单独的字段实际上是一个数组:
public ushort this[int index]
{
get
{
if (index < 0 || index > 7) throw new IndexOutOfRangeException();
switch (index)
{
case 0: return Number1;
case 1: return Number2;
...
}
}
}
在这两种情况下,你的~100字节的字符串变成了只有14个字节 - 还不错:)如果你想进一步按这个,你可以做一点点打包,然后把它更低,只需10 bytes(因为每个数字最多需要11位) - 但这很可能是一种过度杀伤,处理位打包的代码要复杂得多(而且容易出错))。