Управление Памятью Словаря C#

у меня есть Dictionary<string,int> который может содержать более 10 миллионов уникальных ключей. Я пытаюсь уменьшить объем памяти, который это занимает, сохраняя при этом функциональность словаря.

у меня была идея сохранить хэш строки как длинный вместо этого, это уменьшает использование памяти приложений до приемлемого количества (~1.5 gig до ~.5 gig), но я не очень хорошо отношусь к своему методу для этого.

long longKey=
BitConverter.ToInt64(cryptoTransformSHA1.ComputeHash(enc.GetBytes(strKey)), 0);

в основном это котлеты с конца хэша SHA1 и помещает первый кусок в длинный, который я затем использую в качестве ключа. Хотя это работает, по крайней мере, для данных, с которыми я тестирую, я не чувствую, что это очень надежное решение из-за увеличенной возможности ключевых столкновений.

есть ли другие способы уменьшить объем памяти словаря, или метод, который я имею выше, не так ужасен, как я думаю?

[редактирование] Чтобы уточнить, мне нужно сохранить возможность поиска a значение, содержащееся в словаре с помощью строки. Хранение фактической строки в словаре занимает много памяти. Вместо этого я хотел бы использовать Dictionary<long,int> где long является результатом функции хэширования в строке.

6 ответов


поэтому я сделал что-то подобное недавно и по определенному набору причин, которые довольно уникальны для моего приложения, не использовал базу данных. На самом деле я пытался прекратить использовать базу данных. Я обнаружил, что GetHashCode значительно улучшен в 3.5. Одно важное замечание: никогда не храните настойчиво результаты GetHashCode. НИКОГДА. Они не гарантированы, что будут последовательны между версиями рамок.

Так что вам действительно нужно провести анализ ваших данных поскольку различные хэш-функции могут работать лучше или хуже в ваших данных. Вам также нужно учитывать скорость. Как правило, криптографические хэш-функции не должны иметь много коллизий, даже если количество хэшей переходит в миллиарды. Для вещей, которые мне нужно быть уникальными, я обычно использую SHA1 Managed. В целом CryptoAPI имеет ужасную производительность, даже если базовые хэш-функции работают хорошо.

для 64-битного хэша я в настоящее время использую Lookup3 и FNV1, которые являются 32 немного хэшей вместе. Для столкновения оба должны столкнуться, что математически невероятно, и я не видел, чтобы произошло около 100 миллионов хэшей. Вы можете найти код в открытом доступе в интернете.

все еще проводите свой собственный анализ. То, что сработало для меня, может не сработать для тебя. На самом деле внутри моего офиса разные приложения с разными требованиями фактически используют разные хэш-функции или комбинации хэш-функций.

I избегал бы любых недоказанных хэш-функций. Существует столько хэш-функций, сколько людей, которые думают, что они должны их писать. Сделайте свое исследование и тест-тест.


с 10 миллионами нечетных записей вы рассматривали возможность использования базы данных с некластеризованным индексом? Базы данных имеют гораздо больше трюков в рукаве для такого типа вещей.

хэширование, по определению и по любому алгоритму, имеет потенциал столкновений - особенно с большими объемами. В зависимости от сценария, я буду очень осторожен.

использование строк может занять место, но это надежно... если вы находитесь на 64-разрядной это не должно быть слишком большим (хотя это определенно считается "большим";- p)


кстати, криптографические хэши / хэш-функции исключительно плохи для словарей. Они большие и медленные. Решая одну проблему (размер), вы только ввели другую, более серьезную проблему: функция больше не будет равномерно распределять входные данные, тем самым уничтожая единственное самое важное свойство хорошего хэша для приближения к безударной адресации (как вы, кажется, заметили сами).

/ EDIT: как отметил Андрей,GetHashCode is на решение для этой проблемы, так как это его предназначение. И, как в настоящем словаре, вам придется работать вокруг столкновений. Одна из лучших схем для этого -двойное хэширование. К сожалению, единственным 100% надежным способом будет фактическое хранение исходных значений. Иначе вы создали бы бесконечное сжатие, которое, как мы знаем, не может существовать.


почему бы вам просто не использовать GetHashCode() чтобы получить хэш строки?


с реализациями hashtable, с которыми я работал в прошлом, хэш приводит вас к ведру, которое часто является списком ссылок других объектов, имеющих тот же хэш. Хэши не уникальны, но они достаточно хороши, чтобы разделить ваши данные на очень управляемые списки (иногда только 2 или 3), которые вы можете искать, чтобы найти свой фактический элемент.

ключом к хорошему хэшу является не его уникальность, а его скорость и возможности распространения... вы хотите, чтобы он распространялся как можно ровнее.


просто пойти получить SQLite. Вы вряд ли победите его, и даже если вы это сделаете, это, вероятно, не будет стоить времени/усилий/сложности.

базы данных SQLite.