C++ 程序运行时是否受对象在内存中的位置影响?

C++ 程序运行时是否受对象在内存中的位置影响?,c++,c,performance,memory,C++,C,Performance,Memory,我的程序分配的所有资源在启动时略低于1MB,除基本的局部变量外,其他资源不超过1MB。分配最初是由malloc进行的,因此在堆上进行分配,但我想知道将它们放在堆栈上是否会有任何区别 在各种测试中,程序运行时间从3秒到3分钟不等。稳定地访问堆栈似乎要快10%。我所做的更改是对结构进行malloc还是将它们声明为自动变量 我发现的另一个有趣的事实是,当我将对象声明为static时。程序运行速度将降低20~30%。我不知道为什么。我仔细检查了我是否犯了错误,但唯一的区别实际上是static是否存在。静

我的程序分配的所有资源在启动时略低于1MB,除基本的局部变量外,其他资源不超过1MB。分配最初是由
malloc
进行的,因此在堆上进行分配,但我想知道将它们放在堆栈上是否会有任何区别

在各种测试中,程序运行时间从3秒到3分钟不等。稳定地访问堆栈似乎要快10%。我所做的更改是对结构进行malloc还是将它们声明为自动变量

我发现的另一个有趣的事实是,当我将对象声明为
static
时。程序运行速度将降低20~30%。我不知道为什么。我仔细检查了我是否犯了错误,但唯一的区别实际上是
static
是否存在。
静态
变量是否在堆栈中的其他位置而不是自动变量

以前,我有一个相反的经验,在C++类中,当我将const成员数组从非静态数组变成静态数组时,程序运行得更快。内存消耗是相同的,因为该对象只有一个实例


程序运行时是否受对象在内存中的位置影响?即使是这样,编译器能否将对象放在正确的位置以获得最大的效率?

嗯,是的,程序性能受对象在内存中的位置的影响

问题是,除非您对编译器的工作方式、它如何使用特定主机系统的功能(操作系统服务、硬件、处理器缓存等)以及这些功能的配置有深入的了解,否则您将无法始终如一地利用它。即使您成功了,微小的更改(例如升级编译器、更改优化设置、更改进程配额、更改物理内存量、更改硬盘驱动器[例如用于交换空间])也会影响性能,并且预测更改是否会提高或降低性能并不总是容易的。绩效对所有这些因素以及它们之间的相互作用都是敏感的,如果不进行仔细分析,这些因素并不总是显而易见的

程序运行时是否受对象在内存中的位置影响

是的,程序性能将受到内存中对象位置等因素的影响


每当访问堆中的对象时,都通过取消对指针的引用来完成。取消引用指针需要额外的计算才能找到下一个内存地址,而位于您和数据之间的每一个额外指针(例如指针->指针->实际数据)都会使情况稍微恶化。除此之外,它还增加了CPU的缓存未命中率,因为它预期接下来访问的数据实际上并不在连续的内存块中。换句话说,CPU试图优化其管道的假设是错误的,它为错误的预测付出了代价

即使是这样,编译器不能将对象放置在 最有效的地方

C/C++编译器将把对象放在您告诉它的任何位置。如果您使用的是
malloc
,则不应期望编译器将内容放在堆栈上,反之亦然

即使在原则上,编译器也无法做到这一点,因为
malloc
在编译器的工作结束很久之后,在运行时动态分配内存。编译时已知的是堆栈的大小,但内存内容的组织方式完全取决于您


您可能会从编译器优化设置中获得一些好处,但您在优化工作中的大部分好处将更好地用于改进所使用的数据结构和/或算法。

您是否尝试过各种优化级别的测试?@SergeBallesta with gcc 4.9.2,我使用的优化选项总是
-flto-fwhere program-s-O3
malloc
必须找到下一个足够大的内存块并将其标记为已使用。堆栈不存在。
静态
减速可能是因为缓存问题,没有代码就无法判断。本地
静态
变量与全局变量一样驻留在堆上。“本地
静态
变量与全局变量一样驻留在堆上。”-两个计数都是错误的(还有两个向上投票,奇怪)。。。请参阅“每当访问堆中的对象时,都是通过取消对指针的引用来完成的。”是的,但堆栈上的对象也是如此。@TonyK那么,当堆栈对象仍然需要取消对指针的引用时,访问时间会有什么不同呢?你的说法似乎很明显,因为大型对象不会简单地放在寄存器中。正如我在文章和评论中提到的,我不是在玩编译选项,而是在玩我最初的1MB资源最适合的地方。在堆栈中?堆数据段?@xiver77:这可能是您特定的机器架构的结果。通过堆栈指针进行索引的选项可能比通过常规指针进行索引的选项更多。但实际上你所能做的就是尝试不同的选项并仔细地对它们进行基准测试。@TonyK:“堆栈上的对象也是如此”。这不一定是真的。考虑<代码> int *p=(int *)Malc(siZeof(int));*p=5vs
inti=5。显然,
p
的堆地址需要解引用才能访问值,而
i
中的值在堆栈中,不需要解引用b/c
i
不是指针。但是,没有什么可以阻止您执行
inti=5;int*p=&i*p=6,但使用指针访问堆栈数据可能不是它们的最佳用途(即,在复杂的代码中,有人可能会错误地尝试
释放它)。