Новое требует много дополнительной памяти - PullRequest
3 голосов
/ 31 мая 2011

Я делаю приложение, которое будет использовать много динамически создаваемых объектов (трассировка лучей).Вместо того, чтобы использовать [new] снова и снова, я подумал, что просто сделаю простую систему памяти, чтобы ускорить процесс.На данный момент это очень просто, так как мне не нужно много.

Мой вопрос: когда я запускаю это тестовое приложение, использование моего диспетчера памяти использует правильный объем памяти.Но когда я запускаю тот же цикл, используя [new], он использует в 2,5–3 раза больше памяти.Есть ли что-то, чего я здесь не вижу, или [новое] влечет за собой огромные накладные расходы?

Я использую VS 2010 на Win7.Также я просто использую диспетчер задач для просмотра использования памяти процесса.

template<typename CLASS_TYPE>
class MemFact
{
public:
  int m_obj_size; //size of the incoming object
  int m_num_objs; //number of instances
  char* m_mem; //memory block

  MemFact(int num) : m_num_objs(num)
  {
    CLASS_TYPE t;
    m_obj_size = sizeof(t);
    m_mem = new char[m_obj_size * m_num_objs);
  }

  CLASS_TYPE* getInstance(int ID)
  {
    if( ID >= m_num_objs) return 0;
    return (CLASS_TYPE*)(m_mem + (ID * m_obj_size));
  }

  void release() { delete m_mem; m_mem = 0; }
};
/*---------------------------------------------------*/
class test_class
{
  float a,b,c,d,e,f,g,h,i,j; //10 floats
};
/*---------------------------------------------------*/
int main()
{
  int num = 10 000 000; //10 M items
  // at this point we are using 400K memory
  MemFact<test_class> mem_fact(num);
  // now we're using 382MB memory
  for(int i = 0; i < num; i++)
     test_class* new_test = mem_fact.getInstance(i);
  mem_fact.release();
  // back down to 400K
  for(int i = 0; i < num; i++)
     test_class* new_test = new test_class();
  // now we are up to 972MB memory
}

Ответы [ 2 ]

4 голосов
/ 31 мая 2011

Существует минимальный размер для выделения памяти, в зависимости от используемой ЭЛТ.Часто это 16 байтов.Ваш объект имеет ширину 12 байт (при условии x86), поэтому вы, вероятно, тратите как минимум 4 байта на выделение.Диспетчер памяти также имеет свои собственные структуры для отслеживания того, какая память свободна, а какая нет - это не бесплатно.Ваш диспетчер памяти, вероятно, намного проще (например, освобождает все эти объекты за один раз), что по своей сути будет более эффективным, чем то, что делает новый для общего случая.

Также имейте в виду, что если вы строитев режиме отладки распределитель отладки будет дополнять обе стороны возвращенного выделения канареками, пытаясь обнаружить неопределенное поведение.Это, вероятно, перенесет вас через 16-байтовую границу на следующую - вероятно, 32-байтовое распределение, по крайней мере.Это будет отключено при сборке в режиме релиза.

0 голосов
/ 31 мая 2011

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

На самом деле, - это действительный шаблон, известный как пул объектов, который похож на ваш, но не сосет. Простой ответ заключается в том, что operator new должен быть очень гибким - его объекты должны жить вечно, пока не будет вызван delete, и их деструктор тоже должен быть вызван, и все они должны иметь совершенно отдельные, независимые времена жизни. Он должен иметь возможность выделять объекты переменного размера и любого типа в любое время. Ваш MemFact не соответствует ни одному из этих требований. К пулу объектов также предъявляются меньшие требования, и из-за этого значительно быстрее, чем обычный new, но он также не полностью терпит неудачу на всех других фронтах.

Вы пытаетесь сравнить почти полностью гнилое яблоко с апельсином.

...