-2

我对此感到困惑..这个:

for (int j=0; j<100; ++j) {
  long* data = new long[0];
}

clock_t launch = clock();
sim.Run();
clock_t done = clock();

运行速度比仅此一项快 50%:

clock_t launch = clock();
sim.Run();
clock_t done = clock();

这是在使用 -O3 时。如果我使用 -O0 则执行时间没有区别。不管是long还是short不重要。向量的长度也不会改变任何东西。我没有data在任何地方使用。如果我delete[] data;在循环中,改进就会消失。当我将迭代次数减少到以下100时,性能增益会降低;上面100没有任何区别。

如果这是 Java,我会认为我正在触发 GC,但这是 C++!此外,它是一个单线程软件,所以它不应该是内存共享优化的东西。

这会是什么?这种行为是否是我的代码中内存管理不善的症状?谢谢!

4

1 回答 1

3

你怎么说,“长 50%”?我们是在谈分钟,还是在谈秒?

在几秒钟的情况下,它可能只是一个同步错误(两个clock_t可能相差最多两秒,而实时变化不会超过百分之几秒)。

但我的猜测是我们正在寻找更长的时间。并且在不查看您的代码的情况下,我怀疑通过分配“泄漏”的内存可以“启动”内存堆,以便以后更快地检索信息。

这告诉我,是的,您的内存管理可能不是最优的,并且可能会从预分配和重用内存(“对象池”)中受益。

“启动”内存堆,我的意思是内存分配通常需要内存管理器来跟踪堆内存。在更简单的情况下使用链表。即使您没有垃圾收集器,您仍然有一个内存管理器,它位于malloc,free等后面realloc(以及new,就此而言)。MM可以通过向操作系统请求大块,然后将其分配给应用程序,和/或通过“调整”您在请求中发出的请求来操作,这些请求可能由操作系统更好/更快地处理。例如,操作系统通常“看到”页面中的内存1K,4K,64K,取决于。如果您为自己分配 50 个 10 字节的字符串,它们可能会发现自己位于不同的页面并浪费大量内存。MM 在看到你第一次请求 10 字节时可能会分配 4096,然后将它们以 10 字节为单位打包给你。

现在(我要在这里冒险了!),假设您的应用程序需要分配与整个页面相等的内存,分十块。由于程序本身需要少量开销,您的初始堆分配是四分之一页。

所以你继续分配你的十个块。前六个适合部分空的页面零;接下来的四个请求新分配一个新页面,即第一页。

分配完成后,您开始在块之间来回处理数据,而不会意识到它们位于两个不同的页面中。根据操作系统、编译器、优化和天气预报,这可能意味着这些操作会产生开销

现在让我们假设您分配并泄漏了四分之三的页面。然后,当您分配第一个块时,它不适合第 0 页,而第一个 - 和剩余的 9 个 - 块全部进入并适合第 1 页。如果 -O3 优化利用同页数据访问,您将体验到依赖于编译器的性能提升。

请记住,这只是一个临时假设。在我看来这似乎是合理的,但这并不能真正保证任何事情:-)

有关 libc 标准内存管理的更多详细信息(其他存在)here

http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_3.html#SEC27

您还可以查看Google 的 C++ 工具

于 2012-10-11T11:06:17.520 回答