【问题标题】:C++ stack memory and CPU cacheC++ 堆栈内存和 CPU 缓存
【发布时间】:2014-05-20 13:07:25
【问题描述】:

我听说放置在 C++ 堆栈中的数据最有可能出现在 CPU 缓存中。
http://www.gamedev.net/topic/564817-stack-and-cache-question-optimizing-sw-in-c/#entry4617168

“堆栈是存储数据最有效的地方,因为同样的 内存地址范围被一次又一次地重用。”

由于隐含的操作顺序,最常访问的数据在 堆栈几乎肯定总是在 L1 缓存中。

这是真的吗?


我的意思是,尝试将频繁访问的数据存储在堆栈中真的比堆中更好吗?

【问题讨论】:

  • 我认为,如果您想要一个比“这取决于您的数据大小和缓存大小”更好的答案,那么您将不得不更加具体。
  • IMO 这是一个太大的简化。现在有更多的变量需要考虑。为什么频繁访问的堆分配内存块被缓存的机会更少?顺便说一句,L1 缓存非常小,您使用几 KB 的数据吗?
  • @Adriano 嗯,我认为那些,来自 100-500 Kb 的堆栈。好吧,不是在 L1 中,但至少在某个地方(在缓存中)? :)
  • 但是堆栈并不是那么邪恶,即使它并不总是/全部缓存。这取决于您的数据(大小和性质)和您的代码(算法和路径)。如果您的“瓶颈”是一个大型矩阵乘法例程,那么跳转将是您的敌人(如果您的所有单线程应用程序堆栈都保存在缓存中,您将不会注意到任何好处)。总结一下:不,IMO 断言太天真并且过于简单化了一切(所以你可能会在错误的事情上浪费时间)。
  • 一个不错的经验法则。在堆栈上分配的对象比使用 new() 分配的相同对象更有可能在 L1 缓存中。但这都是次要的。盲目地遵守这条规则会给你带来麻烦。根据具体情况,还有其他更重要的原因将事物放入堆栈或不将它们放入堆栈。

标签: c++ caching stack-memory


【解决方案1】:

C++ 标准的确切实现是一个实现细节:它因编译器而异,因平台而异……

现在,尽管理论上您可以为 C++ 使用拆分堆栈,但主要实现使用的是连续的内存段(大小不一)。

这种连续性和频繁重用确实很容易获得缓存的好处,但它也不是灵丹妙药。实际上,您还可以为缓存反弹创建人工场景:如果您的 L1 缓存很小(32k ?)并且具有 2 路关联性,那么您可以轻松地制作需要访问 L2 缓存的场景。只需在堆栈上使用 64k 数组(它足够小,不会炸毁它),然后在循环中重复访问 0、16k、32k 和 48k 的数据:它应该会触发大量驱逐并需要从 L2 缓存中获取。

因此,堆栈本身并不是对缓存如此友好,而是它的使用是可预测的和众所周知的。您可以使用定制的分配器获得相同的缓存优势(尽管分配会稍微慢一些)。

另一方面,使用堆栈还有其他优点和缺点:

  • 缺点:如果您尝试消耗过多,则会出现 Stack Overflow。
  • 缺点:如果覆盖堆栈上的数组,可能会损坏堆栈本身,这是调试的噩梦(所谓的堆栈粉碎攻击也使用它)。
  • 优势:C++ 具有利用堆栈行为的特定模式(RAII、SBRM)。确定性的“撤消”操作是编程的乐趣。

所以最后我会谨慎地根据潜在的缓存行为在堆栈和堆之间做出决定。

【讨论】:

  • +1 for “缺点:如果覆盖堆栈上的数组,可能会损坏堆栈本身,这是调试的噩梦……”。对我来说 90% 的工作是在 5% 的指针相关的错误上,现在它总是我检查的第一件事......
  • @Matthieu M. 你也可以看看这个吗? stackoverflow.com/questions/30555623/…这个问题也是基于缓存的
猜你喜欢
  • 2020-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-16
  • 2012-09-06
  • 2017-01-04
  • 2018-09-27
  • 2011-10-21
相关资源
最近更新 更多