Что лучше с точки зрения выделения памяти - подобъект или указатель на отдельный объект? - PullRequest
5 голосов
/ 30 июля 2010

У меня есть следующая проблема в программе Visual C ++ 9.Существует огромный объект, который логически содержит несколько подобъектов.Я могу либо сохранить подобъекты внутри объекта, либо сохранить указатели на подобъекты, выделенные отдельно.

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

Вот как развивается моя мысль:

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

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

Как мне принять решение?Существуют ли какие-либо методы для решения, следует ли мне выбирать объект меньшего размера или более крупный с учетом приведенных выше соображений?

Ответы [ 6 ]

2 голосов
/ 30 июля 2010

Выделение нескольких больших объектов приведет к фрагментации памяти меньше, чем выделение большего количества меньших объектов. Что еще более важно, поскольку больший процент ваших объектов точно такого же размера, вы часто сможете повторно использовать освобожденный блок в том виде, как он есть. Разделение вашего объекта на большее количество более мелких объектов обычно приводит к фрагментации больше проблемы, а не меньше.

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

1 голос
/ 30 июля 2010

Я бы не советовал принимать это решение на основе ощутимых преимуществ в отношении фрагментации. Вместо этого примите решение, основанное на дизайне вашего класса.

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

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

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

1 голос
/ 30 июля 2010

Я бы сказал, что вы получите меньше фрагментации памяти, если будете хранить один большой объект, а не множество маленьких. Подумайте об этом таким образом. Если у вас есть 100 МБ памяти и вы выделяете 1 50 МБ объекта, то в худшем случае у вас будет два 25 МБ доступных блока.

Однако если вы выделите два блока по 25 МБ, в худшем случае у вас может быть 3 блока по 16 МБ. Это скорее фрагментация, а не меньше.

0 голосов
/ 30 июля 2010

Как уже упоминали другие, ваше предположение о том, что много небольших распределений лучше для фрагментации, чем меньшее количество больших распределений, неверно.

Если фрагментация представляет серьезную проблему, одним из лучших инструментов, которые вы можете использовать, является объединенная память. В вопросе вы говорите, что «подобъект всегда одного размера». Если это так, у вас есть большая возможность значительно сократить количество выделений и фрагментацию кучи. Просто создайте свой собственный объект-распределитель, который раздает блоки памяти размером sizeof(SubObject). Ваш внешний объект будет хранить указатель на подобъект, который был выделен вашим распределителем. Когда он хочет освободить, он передает память обратно объекту-распределителю. Объект распределителя вместо вызова delete сохранит блок памяти и выдаст его в следующий раз, когда его попросят о выделении. Объект распределителя будет хранить список таких блоков и перерабатывать их. Это значительно сократит количество выделений кучи, которые вы делаете.

0 голосов
/ 30 июля 2010

Если вы используете умный указатель, вам не нужно беспокоиться об уничтожении ваших объектов, поэтому код примерно эквивалентен использованию агрегированного объекта (за исключением небольших накладных расходов на память и производительность).Однако опыт показывает, что спецификация со временем меняется (вам может понадобиться поменять подобъекты между объектами позже), более гибко использовать указатель, чем подобъект.И в худшем случае (если у вас есть память или производительность) и вы хотите вернуться к подобъекту, вы можете легко создать подобъект и установить на него старый указатель, чтобы не изменять никакие биты кода, кроме конструктора,вот так (в псевдокоде) (вы даже можете использовать #ifdef, вы можете изменить его, когда захотите сделать несколько тестов, если это необходимо)

class A 
{
#ifdef SUBOBJECT
   B __b; 
#endif
   B *b;
   A()
   {
#ifdef SUBOBJECT
     *b = &__b;
#else
     *b = new B();
#endif     
   };

  void f()
  {
    b->f();
  }
}
0 голосов
/ 30 июля 2010

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

Простой факт состоит в том, что сочинение с подобъектами является самым быстрым и наименьшим вариантом во всех возможных отношениях.Если вы можете это сделать, сделайте.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...