1

我有近 1,000,000 条记录的数组,每条记录都有一个“文件名”字段。

有许多文件名完全相同的记录。

我的目标是通过去重字符串实例(文件名实例,而不是记录)来改善内存占用。

.NET Framework 2.0 是一个约束。这里没有 LINQ。

我为重复数据删除编写了一个通用(和线程安全)类:

public class Deduplication<T>
    where T : class
{
    private static Deduplication<T> _global = new Deduplication<T>();

    public static Deduplication<T> Global
    {
        get { return _global; }
    }

    private Dictionary<T, T> _dic;// = new Dictionary<T, T>();
    private object _dicLocker = new object();

    public T GetInstance(T instance)
    {
        lock (_dicLocker)
        {
            if (_dic == null)
            {
                _dic = new Dictionary<T, T>();
            }

            T savedInstance;
            if (_dic.TryGetValue(instance, out savedInstance))
            {
                return savedInstance;
            }
            else
            {
                _dic.Add(instance, instance);
                return instance;
            }
        }
    }

    public void Clear()
    {
        lock (_dicLocker)
        {
            _dic = null;
        }
    }
}

这个类的问题是它增加了更多的内存使用,并且它一直呆在那里直到下一次 GC。

我正在寻找一种减少内存占用的方法,而无需增加大量内存使用,也无需等待下一次 GC。我也不想使用GC.Collect(),因为它会冻结 GUI 几秒钟。

4

3 回答 3

1

如果你不想实习你的字符串。您可以对 Java 8 的字符串重复数据删除(由堆上的 GC 完成)采取类似的方法。

  1. 在添加字符串时获取字符串的哈希值。
  2. 如果散列不存在,则将其与字符串关联。
  3. 如果散列确实存在,则逐个字符地比较具有相同散列的字符串。
  4. 如果您的比较匹配,则存储对原始字符串的引用而不是新副本。

假设您有很多重复项,这将减少您的内存占用,但是实习可能会执行得更好,因为它是在堆上的较低级别完成的。

于 2015-01-15T15:36:50.243 回答
0

您可以将所有字符串粘贴在前缀树中。根据您的路径名称的不同,这应该自动删除公共子字符串的重复数据。在这个 C# 实现中,在 google 上进行了快速搜索。

于 2013-09-13T03:57:05.943 回答
-1

我建议您仔细检查您的内存占用是否尚未优化。.NET 会自动在堆上实习重复字符串,这意味着您可以让多个相同String的对象指向相同的内存地址。只要打电话String.Intern(targetString)。这就是为什么Strings 是不可变的并且StringBuilder存在的原因。

更直接的是,如果您在堆上的剩余字符串遇到问题,您可以在完成后立即启动垃圾收集(甚至在运行期间定期):

GC.Collect();

于 2013-09-12T23:43:20.403 回答