2013-09-12 4 views
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(), потому что он замораживает графический интерфейс на пару секунд.

+0

Нет LINQ, нет ответа: - & ( – evanmcdonnal

+0

Если я правильно прочитал, у вас возникли две проблемы: одна из них заключается в том, что все строковые объекты все же должны сначала создаваться, а затем собирать мусор после их поиска Во-вторых, словарь не может быть наиболее пространственно эффективной структурой для вашей потребности. Какова средняя длина имени файла и каково отношение дубликатов? – hatchet

+0

Я создаю эти строки в своем коде из кодированных байтов UTF-16 средняя длина имени файла - 26,2 символа.6% имен файлов дублируют другое имя файла в других 42,4%. – DxCK

ответ

-1

Я бы рекомендовал вам дважды проверить, что ваш объем памяти еще не оптимизирован. .NET автоматически ставит повторяющиеся строки в куче, что означает, что вы можете иметь несколько идентичных объектов String, указывающих на один и тот же адрес памяти. Просто позвоните по номеру String.Intern(targetString). Вот почему String s неизменяемы, и существует StringBuilder.

Более немедленно, если у вас возникли проблемы с оставшимися строками в куче, вы можете начать сборку мусора сразу после завершения (или даже периодически во время бега):

GC.Collect();

+1

Я думал, что это только для струнных литералов. Для нелитералов вам нужно будет использовать String.Intern для получения того же самого (и String.Intern не будет хорошо для его цели). – hatchet

+0

Ах, ты прав. Тем не менее, String.Intern() может быть только билетом. –

+0

Проблема с String.Intern заключается в том, что строки остаются там до тех пор, пока CLR не прекратится (в основном навсегда) ... даже после завершения вашего приложения. – hatchet

0

Вы можете вставлять все строки в дерево префикса. В зависимости от того, как различны ваши имена путей, это должно автоматически дедуплицировать общие подстроки. Быстрый поиск по google дал в this C# implementation.

1

Если вы не хотите ставить свои строки. Вы можете использовать аналогичный подход к дедупликации строк Java 8 (что делает GC в куче).

  1. Получите значения хэша строк при их добавлении.
  2. Если хеш не существует, сопоставьте его со строкой.
  3. Если хеш существует, сравните строки с одним и тем же символом хэша символом.
  4. Если сопоставить это сравнение, сохраните ссылку на исходную строку вместо новой копии.

Это уменьшит объем памяти, если у вас много дубликатов, но интернирование, вероятно, будет намного лучше, как это делается на более низком уровне прямо на куче.