Ответ 1
ОК, поэтому реальный вопрос здесь: "У меня есть огромный набор данных, который я храню в памяти, как я могу оптимизировать его производительность как во времени, так и в памяти?"
Несколько мыслей:
- Вы абсолютно правы, чтобы ненавидеть и бояться бокса. У бокса большие издержки. Во-первых, да, объекты в штучной упаковке занимают дополнительную память. Во-вторых, объекты в коробке сохраняются в куче, а не в стеке или в регистрах. В-третьих, это сбор мусора; каждый один из этих объектов должен быть опрошен в GC-время, чтобы узнать, содержит ли он ссылку на другой объект, чего он никогда не будет, и что много времени на поток GC. Вам почти наверняка нужно что-то сделать, чтобы избежать бокса.
Динамический не так; это бокс плюс целый ряд других накладных расходов. (Динамика С# очень быстро по сравнению с другими динамическими системами диспетчеризации, но она не является быстрой или малой в абсолютном выражении).
Это грубо, но вы могли бы рассмотреть возможность использования структуры, чей макет разделяет память между различными полями - например, объединение в C. Выполнение действительно действительно грубо и вовсе не безопасно, но может помочь в таких ситуациях. Сделайте поиск в Интернете для "StructLayoutAttribute"; вы найдете учебники.
- Длинный, двойной или струнный, правда? Не может быть int, float или string? Действительно ли данные действительно превышают несколько миллиардов или точнее до 15 знаков после запятой? Разве int и float не выполняли эту работу в 99% случаев? Они в два раза меньше.
Обычно я не рекомендую использовать float over double, потому что это ложная экономика; люди часто экономят этот путь, когда у них ОДИН номер, например, экономия в четыре байта будет иметь значение. Разница между 42 миллионами поплавков и 42 миллионами удваивается.
-
Есть ли регулярность в данных, которые вы можете использовать? Например, предположим, что из ваших 42 миллионов записей есть только 100000 действительных значений, например, для каждого длинного, 100000 значений для каждого двойного и 100000 значений для каждой строки. В этом случае вы производите индексированное хранилище некоторого типа для длин, удвоений и строк, а затем каждая запись получает целое число, где младшие биты являются индексом, а два верхних бита указывают, какое хранилище нужно извлечь из него. Теперь у вас есть 42 миллиона записей, каждый из которых содержит int, а значения хранятся в какой-то красивой компактной форме где-то еще.
-
Хранить логические значения в виде битов в байтах; писать свойства, чтобы выполнить смещение бит, чтобы получить их. Сохраните несколько байтов таким образом.
-
Помните, что память на самом деле является дисковым пространством; ОЗУ - это всего лишь удобный кэш. Если набор данных будет слишком большим для хранения в ОЗУ, тогда что-то собирается распечатать его на диск и прочитать его позже; это может быть вы или она может быть операционной системой. Возможно, вы знаете больше о своей локальности данных, чем в операционной системе. Вы можете записать свои данные на диск в удобной для просмотра форме (например, b-tree) и более эффективно хранить данные на диске и только приносить их в память, когда вам это нужно.