【问题标题】:How does hardware affect the performance of malloc\new on Windows硬件如何影响 Windows 上 malloc\new 的性能
【发布时间】:2016-08-27 07:52:08
【问题描述】:

我正在研究 Windows 7 上的 c++ 应用程序的性能,该应用程序执行大量计算和大量小分配。基本上,我使用 Visual Studio 采样分析器观察到了一个瓶颈,它归结为文件的解析和类型的巨大树结构的创建

class TreeStruct : std::map<key, TreeStructPtr>
{
   SomeMetadata p;
   int* buff;
   int buffsize;
}
  1. 在解析过程中创建了一万个这样的结构
  2. 缓冲区不大,1字节到几百字节

分析器报告最昂贵的功能是

  1. 免费(13000 个独家样品,38% 独家样品)
  2. 新运营商(13000 个独家样品,38% 独家样品)
  3. realloc(4000 个独家样本,13% 独家样本)

我设法优化并减少了对

的分配
  1. 新运营商(2200 个独家样品,48% 独家样品)
  2. 免费(1770 个独家样品,38% 独家样品)
  3. 一些功能(73 个独占样本,1.5% 独占样本)

当我测量客户端等待时间(即客户端使用秒表等待操作处理)时,我的机器上的安装版本从 85 秒开始处理时间缩短到 16 秒的处理时间,这很棒。我继续在我们拥有的最强大的机器上进行测试,并且震惊地发现非优化版本只使用了3.5s,而优化了2s。相同的可执行文件,相同的操作系统...

问题:两台现代机器上怎么会出现这样的差异?

以下是规格: 85s到16s机器

3.5s 到 2s 机器

处理是单线程的。

【问题讨论】:

  • 分配主要是操作系统的事情。除此之外,分配通常很昂贵。通常最好分配一次内存池并重用它们。小分配涉及内核内部相当多的内部管理开销。它也可能与分页和一般系统负载有关。
  • 简·亨克是正确的。最好在需要它们之前一次分配所有结构,然后将它们保存在某种集合中。然后在需要时将它们从收藏中取出。当您不再需要它们时,将它们放回集合中并将它们标记为可用。
  • 你在第二台机器上有更多的缓存和更快的内存。动态分配的内存量是多少?
  • “我正在研究一个 c++ 应用程序的性能 [...],它正在执行 [...] 很多小分配”最大的问题。尽管多年来 CRT 中的堆实现不断改进,但分配仍然带来相当大的开销。如果您避免进行大量小分配(这是 .NET 轻松胜过本机 C++ 程序一个数量级的领域),它通常会显着提高性能。看看 P/Invokes 到本机计算内核中的 .NET 实现是否可以提供更好的性能会很有趣。
  • 基准测试不足永远是常见的原因。当您在启用调试堆的情况下运行慢速版本时,您会看到这样的差异。此外,应该缓慢的是读取文件。比分配内存慢很多很多倍。标准错误是重复运行程序,它不再从磁盘读取文件,而是从文件系统缓存中读取文件。最后但并非最不重要的是可用的页面文件空间量,这是分配内存的唯一实际成本。很大程度上取决于机器上运行的其他内容。

标签: c++ windows performance memory-management benchmarking


【解决方案1】:

正如其他人评论的那样,频繁的小分配是浪费时间和内存。

对于每次分配,都有开销:

  • 函数调用准备
  • 函数调用(执行路径中断;可能重新加载执行 管道)。
  • 查找内存块的算法(可能正在搜索)。
  • 分配内存(将块标记为不可用)。
  • 将地址放入寄存器
  • 从函数返回(顺序执行中的另一个中断)。

不管你的机器速度如何,上面的过程都是大量的执行来分配一小块内存。

现代处理器喜欢将其数据保持关闭(如在数据缓存中)。当它们可以从缓存中获取数据而不是从处理器外部获取数据时,它们的性能会提高(访问时间越慢,值越远,例如片上内存,外部内核;同一板上的片外内存;其他板上的内存; 设备上的内存(例如闪存和硬盘驱动器)。重新分配内存会破坏数据缓存的有效性。

操作系统可能会介入并减慢您的程序。在分配或删除功能中,O.S.可能会检查分页。分页,以简单的形式,是内存区域与硬盘驱动器上的区域交换。当其他更高优先级的任务正在运行并需要更多内存时,可能会发生这种情况。

一种加速数据访问的算法:

  1. 将数据从内存加载到局部变量中(如果可能,寄存器)。
  2. 处理局部变量(寄存器)中的数据。
  3. 存储完成的数据。

如果可以,请将数据放入结构中。一次加载所有结构成员。结构允许将数据放置到连续的内存中(这减少了重新加载缓存的需要)。

最后,减少执行中的分支或更改。研究“循环展开”。您的编译器可能会在更高的优化设置下执行此优化。

【讨论】:

    猜你喜欢
    • 2014-10-16
    • 1970-01-01
    • 1970-01-01
    • 2011-07-07
    • 2013-04-12
    • 1970-01-01
    • 1970-01-01
    • 2019-05-01
    • 1970-01-01
    相关资源
    最近更新 更多