Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在内存分配方面,子对象还是指向单独对象的指针更好? 我在Visual C++ 9程序中有以下问题。有一个巨大的对象,逻辑上包含几个子对象。我可以将子对象存储在对象中,也可以存储指向单独分配的子对象的指针_C++_Visual C++_Memory Management - Fatal编程技术网

在内存分配方面,子对象还是指向单独对象的指针更好? 我在Visual C++ 9程序中有以下问题。有一个巨大的对象,逻辑上包含几个子对象。我可以将子对象存储在对象中,也可以存储指向单独分配的子对象的指针

在内存分配方面,子对象还是指向单独对象的指针更好? 我在Visual C++ 9程序中有以下问题。有一个巨大的对象,逻辑上包含几个子对象。我可以将子对象存储在对象中,也可以存储指向单独分配的子对象的指针,c++,visual-c++,memory-management,C++,Visual C++,Memory Management,这里的关键点是,在一个外部对象中,每种类型的子对象总是有一个实例-它总是具有相同的大小,并且它的生命周期与外部对象的生命周期完全相同,因此上面的两个选择在逻辑上是相同的-程序结构和逻辑不会改变 以下是我的想法发展的过程: 如果我在里面存储子对象,遍历它们的速度会稍微快一点,但这不是我最关心的——我分析了程序,这不是瓶颈 如果我将子对象存储在外部对象中,那么外部对象将占用更多内存,因此我将分配更大的块,与单独分配大量类似的小子对象相比,这可能会使内存碎片化得更多—释放的内存块可能不太可重用(我不确

这里的关键点是,在一个外部对象中,每种类型的子对象总是有一个实例-它总是具有相同的大小,并且它的生命周期与外部对象的生命周期完全相同,因此上面的两个选择在逻辑上是相同的-程序结构和逻辑不会改变

以下是我的想法发展的过程:

  • 如果我在里面存储子对象,遍历它们的速度会稍微快一点,但这不是我最关心的——我分析了程序,这不是瓶颈
  • 如果我将子对象存储在外部对象中,那么外部对象将占用更多内存,因此我将分配更大的块,与单独分配大量类似的小子对象相比,这可能会使内存碎片化得更多—释放的内存块可能不太可重用(我不确定,我只是这样认为)
  • 当然,更少的分配将使程序更快,但这不是很重要-我再次概述了程序,分配时间不是瓶颈
  • 由于每次分配都会导致较大对象的内存开销,因此我实际上会消耗较少的内存,这对处理大量数据的程序很有好处
  • 同时,内存碎片是真正困扰我的-我需要我的程序非常稳定,能够连续运行数月


    我怎么做决定?鉴于上述考虑因素,是否有任何方法可以决定我应该选择较小的对象还是较大的对象?

    分配几个较大的对象将比分配更多的较小对象更少地分割内存。更重要的是,由于对象中有很大一部分大小完全相同,因此通常可以按原样重用已释放的块。将对象拆分为更多更小的对象通常会使碎片问题更严重,而不是更少


    如果您发现碎片确实成为一个问题,您通常希望通过定义自己的分配器来解决这个问题。

    我想说,通过存储一个大对象而不是许多小对象,您将获得更少的内存碎片。这样想吧。如果您有100MB的内存,并且分配了150MB的对象,那么在最坏的情况下,您将有两个25MB的可用块


    然而,若您分配了两个25MB的块,那个么最坏的情况是您可能有3个16MB的块。这是更多的碎片化,而不是更少的碎片化。

    执行尽可能少的单独分配是一个更好的选择。这是因为分配会减少内存和时间方面的开销,此外,连续内存的访问速度要快得多,因为缓存未命中的风险大大降低,而且还会减少碎片(尽管我个人从来没有遇到过碎片问题)

    简单的事实是,在所有可能的方面,使用子对象组合是最快和最小的选择。如果你能做到,就去做


    它还有许多与维护相关的优点,例如自动生成构造函数/赋值运算符。

    如果使用智能指针,则无需担心对象被破坏,因此代码大致相当于使用聚合对象(除了内存和性能方面的轻微开销)。 然而,根据经验,随着时间的推移,规范会发生变化,(以后可能需要在对象之间交换子对象),使用指针比使用子对象更灵活。在更糟糕的情况下(如果您有内存或性能),并且想要返回子对象,您可以轻松地创建一个子对象并使旧指针指向它,这样您就不需要更改除构造函数之外的任何代码位,就像(在伪代码中)那样 (您甚至可以使用#ifdef,您可以随时更改它,如果需要,还可以执行一些基准测试)


    我不建议基于在碎片化方面的感知优势做出这个决定。相反,根据你的课堂设计做出决定

    如果子对象在包含对象的公共接口中不起任何作用,则可以pimpl它们,从而减少外部对象的公共可见接口,并可能减少编译时间。然后,您可以私下定义隐藏在实现中的子对象的实现,而不具有公共可见性

    或者,如果您的设计受益于自动管理的便利性(如果直接包含对象),请使用该方法


    在基于设计考虑做出此决定后,如果您仍然担心碎片问题,解决该问题的正确方法是使用自定义分配器自己控制分配,而不是像其他人在这里提到的那样依赖
    new
    使用的内置分配器的任何特定行为,您认为许多小的分配比较少的大分配更有利于碎片化的假设是不正确的

    如果碎片化是一个大问题,那么可以使用的最佳工具之一就是池内存。您在问题中说“子对象总是具有相同的大小”。如果这是真的,那么您就有很大的机会大大减少分配数量和堆碎片。只需创建您自己的分配器对象,它将分配
    sizeof(子对象)
    的内存块。外部对象将存储指向子对象的指针,该子对象是由分配器分配的。当它想要取消分配时,它将内存交还给分配器对象。分配器对象将保存内存块,而不是调用
    delete
    ,并在下次请求分配时将其分发出去。分配器对象将存储此类块的列表并循环使用
    class A 
    {
    #ifdef SUBOBJECT
       B __b; 
    #endif
       B *b;
       A()
       {
    #ifdef SUBOBJECT
         *b = &__b;
    #else
         *b = new B();
    #endif     
       };
    
      void f()
      {
        b->f();
      }
    }