.NET应该存储引用或值吗?

时间:2010-08-10 00:32:46

标签: .net language-agnostic memory reference performance

我需要在我的对象中存储哪些值已经被处理过,我怀疑什么会花费更多的性能,我应该创建一个存储的数组:

  • 实例引用(它们不是结构,只是引用类)
  • 项目的哈希码
  • 已处理的属性(字符串)名称的名称

更新
我的目标是,处理引用上的数据集合应该花费更少的内存,因为我将获得父实例类型的音调。
我不太关心检索时间(即collection.Contains(reference))。

所以我的问题是以上数组中的内存会花费多少内存。

2 个答案:

答案 0 :(得分:3)

存储对象的引用似乎是最简单和最低内存成本选项

如果你正在使用这个“已经处理过”检查,最好的选择(最快的检查)可能是在你的班级上实施Object.EqualsObject.GetHashCode,然后使用HashSet<T>HashSet<T>对此很好,因为它提供了O(1)Contains() method

如果您无法更改类以允许散列,则可以为对象实现IEqualityComparer

答案 1 :(得分:0)

除非对象的不同值的可能范围小于2 ^ 32,否则.NET样式哈希码不是一个选项,否则您将得到误报(并且考虑到生日悖论,这可能比你可能会想到即使有很好的哈希函数)。 Hashcodes提供了一个零或多个项目的快速链接,然后检查它们是否相等。因此,基于哈希码的解决方案还需要您存储对每个对象的引用,因此在内存中只能存储小于引用的内容。

如果对象不能被垃圾收集(即它们仍然“活着”到应用程序的另一部分),则存储引用的成本将取决于体系结构为4或8个字节。如果它们可能是GC'd,则成本取决于该对象的图形大小。

现在,如果您可以创建自己的小于该对象的无损哈希对象,则可以节省内存。 E.g:

public class ObjectOfInterest
{// all fields public for sake of simplicity in example
    public int ID; // this is important diff id - diff object.
    public int ParID; // this is unimportant, as same for all objects processed here.
    public ParentType Parent; // this is just memoised based on _parID;
    public decimal Val; // this is important.
    public string Name; // unimportant for our purposes.
    public RelatedType Stuff; // memoised based on _id
}

然后我们可以产生一个相关的:

public struct HashObject
{
    private readonly int _id;
    private readonly decimal _val;
    public HashObject(ObjectOfInterest ooi)
    {
        _id = ooi.ID;
        _val = ooi.Val;
    }
    public bool Matches(ObjectOfInterest ooi)
    {
        return _id == ooi.ID && _val == ooi.Val;
    }
    // because one of the options as to how to store *this* is hashing
    public bool Equals(HashObject ho)
    {
        return _id == ho._id && _val == ooi._val;
    }
    public override bool Equals(object obj)
    {
        return Equals(obj as HashObject);
    }
    public int GetHashCode()
    {
        unchecked
        {
            return _val.GetHashCode() ^ (_id << 16) ^ (_id >> 16);
        }
    }
}

现在,我们存储HashObjects并使用它们来记录我们已经完成的工作。在这种情况下,我们将占用存储此结构的至少20个字节,以及我们必须存储它的任何方式的开销。如果ObjectOfInterest现在可以是GC,则更小,如果它们仍然在内存中则毫无意义。

如果您决定将这些存储在HashSet中,那么有一种哈希和相等的方法(可能的值的知识可以改善哈希的好处)。 HashSet不会是最节省内存的集合,尽管可能是因为在所有这些比较中你都会对此产生额外的压力,你需要更快的查找。这是理论上的实验领域(特别是因为细节根据你的对象而变化)。如果您可以查看不断扫描阵列的查找时间复杂度,那么这是您最好的选择。

如果没有可能比原始类型更小的对象允许完全相关的相等比较,那么这种方法不起作用。