【问题标题】:New is taking lots of extra memory新的需要大量额外的内存
【发布时间】:2011-05-31 18:29:21
【问题描述】:

我正在制作一个将使用许多动态创建的对象(光线跟踪)的应用程序。与其只是一遍又一遍地使用 [new],我想我只是制作一个简单的内存系统来加快速度。在这一点上它非常简单,因为我不需要太多。

我的问题是:当我运行这个测试应用程序时,使用我的内存管理器会使用正确的内存量。但是当我使用 [new] 运行相同的循环时,它会使用 2.5 到 3 倍的内存。是我在这里没有看到的东西,还是 [new] 会产生巨大的开销?

我在 Win7 上使用 VS 2010。另外我只是使用任务管理器查看进程内存使用情况。

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
}

【问题讨论】:

  • 您的程序不完整。无论如何,我们可能都不想要这一切。
  • 对不起。我试图编辑史诗格式失败,但有人在我之前编辑并锁定了我猜的我的更改。它不喜欢我放在那里的方式
  • 它可能处于调试模式,有人正在跟踪 1000 万个分配?
  • 它处于调试模式。我不知道这增加了那么多开销。在发布模式下构建它会降低到 600 MB

标签: c++ memory new-operator


【解决方案1】:

内存分配有一个最小大小,具体取决于您使用的 CRT。通常是 16 个字节。您的对象是 12 字节宽(假设 x86),因此您可能在每个分配中浪费了至少 4 个字节。内存管理器也有它自己的结构来跟踪哪些内存是空闲的,哪些内存不是空闲的——那不是空闲的。您的内存管理器可能要简单得多(例如一次性释放所有这些对象),这本质上比 new 在一般情况下所做的更有效。

另外请记住,如果您在调试模式下构建,调试分配器将使用金丝雀填充返回分配的两侧,以尝试检测未定义的行为。这可能会使您超过 16 字节边界并进入下一个边界 - 至少可能是 32 字节分配。当您在发布模式下构建时,它将被禁用。

【讨论】:

    【解决方案2】:

    男孩,我当然希望没有人愿意从您的内存管理器中分配任何非 POD。或动态大小的对象。并且不介意为每种类型实例化它。或者一次创建尽可能多的。或者让它们的生命周期比MemFact 更长。

    事实上,一种称为对象池的有效模式,它与您的类似,但并不糟糕。简单的答案是operator new 需要非常灵活——它的对象必须永远存在,直到delete 被调用——并且它们的析构函数也必须被调用,并且它们都必须具有完全独立的生命周期。它必须能够在任何时候分配任何类型的可变大小对象。您的MemFact 不符合这些要求。对象池的要求也更少,并且 比普通的 new 快得多,但它也不会在所有其他方面完全失败。

    您正在尝试将一个几乎完全腐烂的苹果与一个橙子进行比较。

    【讨论】:

    • 我说...它不需要灵活。我将它用于 2 个简单的类,只要 MemFact 存在,它们就存在。我问的是[新]......不是我的班级。没必要粗鲁。
    猜你喜欢
    • 2015-02-04
    • 1970-01-01
    • 2021-12-19
    • 2011-06-18
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多