В C # /. NEt динамический тип занимает меньше места, чем объект? - PullRequest
10 голосов
/ 28 января 2011

У меня есть консольное приложение, которое позволяет пользователям указывать переменные для обработки. Эти переменные бывают трех видов: строковые, двойные и длинные (двойные и длинные являются наиболее часто используемыми типами). Пользователь может указать любые переменные, которые ему нравятся, и в любом порядке, чтобы моя система могла справиться с этим. С этой целью в моем приложении я хранил их как объекты, а затем приводил их в соответствие с необходимостью. например:

public class UnitResponse
{
    public object Value { get; set; }
}

Насколько я понимаю, объекты в штучной упаковке занимают немного больше памяти (около 12 байт), чем тип стандартного значения.

Мой вопрос: будет ли эффективнее использовать динамическое ключевое слово для хранения этих значений? Это может обойти проблему упаковки / распаковки, и если она будет более эффективной, как это повлияет на производительность?

EDIT

Для обеспечения некоторого контекста и предотвращения "вы уверены, что используете достаточно ОЗУ, чтобы беспокоиться об этом", в моем худшем случае у меня 420 000 000 точек данных, о которых нужно беспокоиться (60 переменных * 7 000 000 записей). Это в дополнение к куче других данных, которые я храню о каждой переменной (включая несколько логических значений и т. Д.). Таким образом, сокращение памяти оказывает ОГРОМНОЕ влияние.

Ответы [ 4 ]

19 голосов
/ 29 января 2011

ОК, поэтому вопрос real здесь такой: «У меня чертовски огромный набор данных, который я храню в памяти, как мне оптимизировать его производительность как во времени, так и в пространстве памяти?»

Несколько мыслей:

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

Динамично, не правда ли?это бокс плюс много других накладных расходов.(Динамическая C # очень быстрая по сравнению с другими динамическими системами диспетчеризации , но она не быстрая и не маленькая в абсолютном выражении).

Это брутто, но вы можете рассмотреть возможность использования структуры, разделяющей макетпамять между различными полями - как объединение в C. действительно очень грубая и совсем не безопасны , но это может помочь в подобных ситуациях.Выполните поиск в Интернете по запросу "StructLayoutAttribute";Вы найдете учебники.

  • Длинные, двойные или струнные, правда?Не может быть int, float или string?Действительно ли данные превышают несколько миллиардов или имеют точность до 15 знаков после запятой?Разве int и float не выполняют эту работу в 99% случаев?Они вдвое меньше.

Обычно я не рекомендую использовать float over double, потому что это ложная экономия;люди часто экономят таким образом, когда у них ОДИН номер, например, экономия четырех байтов будет иметь значение.Разница между 42 миллионами чисел с плавающей запятой и 42 миллионами удваивается.

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

  • Храните логические значения как биты в байте;написать свойства, чтобы сделать сдвиг битов, чтобы получить их.Сохраните таким образом несколько байтов.

  • Помните, что память на самом деле является дисковым пространством;RAM - это просто удобный кеш.Если набор данных будет слишком большим для хранения в ОЗУ, то что-то вернет его обратно на диск и позже прочитает;это может быть вы или операционная система.Вполне возможно, что вы знаете больше о вашем местонахождении данных, чем операционная система.Вы можете записывать свои данные на диск в удобной для просмотра страниц форме (например, в виде b-дерева) и более эффективно хранить данные на диске и вносить их в память только тогда, когда это необходимо.

14 голосов
/ 28 января 2011

Я думаю, что вы, возможно, смотрите не на то, что здесь.Помните, что делает динамика. запускает компилятор снова, в процессе, во время выполнения .Он загружает сотни тысяч байтов кода для компилятора, а затем на каждом сайте вызова он создает кеши, содержащие результаты недавно выданного IL для каждой динамической операции.Вы тратите несколько сотен тысяч байтов, чтобы сэкономить восемь.Это кажется плохой идеей.

И, конечно, вы ничего не сохраняете.«динамический» - это просто «объект» в модной шляпе.«Динамические» объекты по-прежнему упакованы.

3 голосов
/ 28 января 2011

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

Кроме того, действительно ли все эти усилия стоят 12 байт на объект? Конечно, есть лучшее использование вашего времени, чем экономия нескольких килобайт (если это) ОЗУ? Вы доказали, что использование ОЗУ вашей программой на самом деле является проблемой?

2 голосов
/ 28 января 2011

Нет.Dynamic просто сохранит его как объект.

Скорее всего, это микрооптимизация, которая принесет мало пользы.Если это действительно становится проблемой, то есть другие механизмы, которые вы можете использовать (универсальные), чтобы ускорить процесс.

...