【问题标题】:Time for deleting pointers删除指针的时间
【发布时间】:2011-03-07 18:44:25
【问题描述】:

嘿社区,

我有一个关于删除指针的小问题。

我正在使用尺寸为 1024x1024 的指针对指针矩阵。由于我是动态创建它们的,因此我在程序结束时删除了为它们分配的空间。但是在通常的循环中这样做会花费很多时间——我使用处理器的时钟频率测量了大约 2 秒。当程序只运行 15 秒时,2 秒是巨大的——另外:使用这些分配的指针的函数被调用不止一次......。

这是测量的时间关键型代码,包括测量:

time=clock();
for(i=0;i<xSize;i++){            //xSize is dynamic, but 1024 for the measurement
    delete [] inDaten[i];
    delete [] inDaten2[i];
    delete [] copy[i];
}
delete inDaten; delete inDaten2; delete copy;
time=clock()-time;
     time/=CLOCKS_PER_SEC;

删除指针总是那么长吗?还是我只是做错了事?

我希望这里有人可以帮助我解决这个问题。因为我正在优化一个相当复杂的程序以更快地运行,所以我不能使用那些 2 秒的代码。与所有其他部分相比,它太慢了。但我仍然需要能够动态地实现这段代码。智能指针可能会有所帮助,但如果我理解正确,它们也需要时间来删除自己 - 只是在不同的时间......

感谢您的回答!

酒吧老板

编辑:我刚刚发现,测量这些删除计算非常慢,因为我没有在发布模式下编译它。自从调试器开始发挥作用后,我测量了这些(最终是虚幻的)数字,这些数字让我很头疼。最终程序会自动优化到足以使删除几乎没有时间。

无论如何:感谢所有有用的答案!他们给了我很多额外的知识和思考的东西!!!!

【问题讨论】:

  • inDateninDaten2copy中的对象是什么类型?它们只是整数或类似的东西,还是真实的对象?
  • 你需要动态分配一切吗?您需要这么多单独分配吗?是否可以重写程序以将数据存储在更少、更大的分配中?
  • 在我的上网本上,删除 double[] 不会到达下一个时钟滴答,所以要么你在运行时附加了调试器,要么在数组中元素的析构函数中发生了一些昂贵的事情.
  • @Pete:据我所知,他正在删除数百万个。
  • @Jalf 我正在运行他给出的 xSize = 1024 的代码,所以它是三个参差不齐的数组,每个数组都包含一百万个双精度数

标签: c++ pointers memory-management


【解决方案1】:

delete[] 还将为数组的每个元素调用析构函数,这会增加时间,除非析构函数是微不足道的。

除此之外 - 是的,动态内存分配相对昂贵。如果你不能容忍它 - 尝试分配更少的更大尺寸的块,或者在时间关键的东西中不进行动态分配。

智能指针不会有太大帮助 - 它们会在内部执行相同的释放操作。它们不是为了加速,而是为了设计方便。

【讨论】:

    【解决方案2】:

    这是一个有趣的线程“Memory Allocation/Deallocation Bottleneck?

    分配和解除分配需要很长时间,因此是您最常见的成本高昂的操作之一。这是因为堆管理必须处理很多事情。通常在调试模式下还会对内存块进行更多检查。如果您在发布配置中具有相同的时间,我会感到惊讶,通常至少有 2 个因素之间存在一个因素。使用 私有堆,您可以显着增加事情。如果您总是分配相同大小的对象,那么内存池可能是最好的选择。

    【讨论】:

      【解决方案3】:

      如果您在程序结束时删除它们,而无论是否运行析构函数都无关紧要,只需忽略删除 - 内存将被操作系统释放。否则,尝试使用单一间接,即没有指针到指针的数组。除了减少删除时间,这也将提高参考的局部性。

      【讨论】:

      • 无法保证操作系统会释放任何内存。
      • @Yacoby:除非操作系统本身给出这样的保证。任何现代(桌面)操作系统都可以做到。
      • 无论操作系统是否在退出时清理进程内存,依靠这样的拐杖仍然是不好的做法。最好使用更适合快速释放的分配器,和/或重新设计代码以最小化释放(当然不会引入泄漏)。
      • @Void:AFAIK 所有现代垃圾收集运行时环境都依赖于这种行为,如果它提高性能,它们被设计为引入泄漏。
      【解决方案4】:

      看来问题出在您的数据结构上。为什么需要这么多动态分配?有什么办法可以减少分配次数?

      如果释放指针需要 2 秒,那么分配它们可能至少需要同样多的时间。

      只要提前退出程序就可以避免释放它们。 C++ 不保证分配的内存会发生什么,但您的操作系统可能会这样做,所以在实际方面,这可能是一种将执行时间缩短 2 秒的简单方法。

      但这仍然留下 > 2 秒的分配时间。

      我认为,最好的办法是尝试更好地构建数据。您能告诉我们当前矩阵的结构吗?

      【讨论】:

      • 使用一维矩阵可以节省时间!你对结构是正确的。矩阵包含图像的灰度(如 1024x1024 等)。但仍然:分配比释放快得多(按测量)
      【解决方案5】:

      这不应该是:

      delete [] inDaten; delete [] inDaten2; delete [] copy;
      

      因为使用时,它们显然是数组。 (至少它们看起来也是,你没有提供足够的上下文)。

      【讨论】:

      • 是的,应该是 - 已经改变了,但它不会改变时间数字 =)。
      【解决方案6】:

      您没有说数组中的对象有多大,但如果它们足够大,则可能有一部分内存被换出并需要换回(或者可能只是重新映射回进程空间),这就是你看到的时间。

      【讨论】:

        【解决方案7】:

        尝试创建自己的内存分配方法,以减少销毁时间。

        例如,从 Os 请求一块内存并为其分配数组,以便您可以在一次操作中释放整个块。

        【讨论】:

          【解决方案8】:

          非常感谢所有快速的答案!!!很高兴看到有人在帮忙=)。仍然对于我的问题,似乎我必须处理这种时间损失,因为我需要动态数组作为最终不执行的较小子程序中的临时矩阵。

          无论如何:再次感谢!祝你有美好的一天!

          酒吧老板

          【讨论】:

            【解决方案9】:

            如果数组中指向的对象具有重要的析构函数,那么在不首先解决该问题的情况下,您将无法显着改善运行时间。否则:

            与其使inDaten, inDaten2 and copy 数组大小为isize 的指针指向大小为isize 的数组,为什么不将它们设为大小为isize*isize 的数组,而不是用array[i][j] 寻址单个项目@ 用@987654326 寻址它们@。 这样一来,您就可以拨打delete [] 进行清理。

            【讨论】:

              【解决方案10】:

              对此的优化是按块分配内存,分配带有新位置的单个指针,删除时只删除整个块。

              您必须小心,因为此选项隐含地不会调用每个分配有新位置的对象的析构函数。

              【讨论】:

                【解决方案11】:

                如果矩阵中的指针引用的所有对象都是相同类型(或至少相同大小),您可以分配一大块内存来保存它们并就地初始化它们。

                【讨论】:

                  【解决方案12】:

                  如果您已确定内存分配/解除分配是瓶颈并希望这更快,第一个明显的解决方案是为您的数组使用连续缓冲区。您仍然可以提供一个矩阵接口,像访问二维数组一样访问它们。

                  // Rudimentary Implementation
                  template <class T>
                  class SquareMatrix
                  {
                  public:
                      explicit SquareMatrix(int i_size): 
                          size(i_size), mat(new T[i_size * i_size]) {}
                  
                      ~SquareMatrix()
                      {
                          delete[] mat;
                      }
                  
                      // could also be column depending on row-major/col-major
                      T* operator[](unsigned int row)
                      {
                          return mat + row * size;
                      }
                  
                      // could also be column depending on row-major/col-major
                      const T* operator[](unsigned int row) const
                      {
                          return mat + row * size;
                      }
                  
                  private:
                      unsigned int size;
                      T* mat;
                  };
                  

                  第二件显而易见的事情是,不是三个矩阵,而是一个由一个结构组成的矩阵,该结构包含您需要的所有数据。这是假设一个元组矩阵就足够了,您发布的代码似乎就是这种情况。

                  如果你真的想要硬核并且需要多个矩阵,那么为此编写你自己的内存分配器。您可以一次为多个矩阵分配内存,然后使用placement new 简单地构造它们。如果您想这样做,则需要进一步阅读和学习,因为编写内存分配器并非易事:您需要考虑对齐等问题,但这是最快的方法。

                  我建议您仍然使用分析器而不是依赖时序测试并对代码进行适当的调用图分析。这将准确地告诉您在哪里花费了多少时间。例如,可能是矩阵中对象的构造/销毁并不便宜。

                  除了明显的算法效率低下之外,即使是知识渊博的程序员也经常对代码中的瓶颈不正确。如果效率是一个主要问题,分析器是您最好的朋友。

                  【讨论】:

                    猜你喜欢
                    • 2013-04-14
                    • 2010-09-08
                    • 2011-09-18
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-06-09
                    • 2015-08-09
                    • 1970-01-01
                    • 2012-01-05
                    相关资源
                    最近更新 更多