C++ 哪个更快:堆栈分配还是堆分配
这个问题听起来可能相当简单,但这是我与另一位与我一起工作的开发人员进行的辩论 我在尽可能地将东西堆叠分配,而不是堆分配。他跟我说话,在我身后看着我,并评论说这是没有必要的,因为他们的表现是一样的 我一直认为,增加堆栈的时间是恒定的,堆分配的性能取决于当前堆在分配(找到适当大小的洞)和取消分配方面的复杂性(折叠孔以减少碎片,因为如果我没有弄错的话,许多标准库实现在删除过程中都会花费时间)C++ 哪个更快:堆栈分配还是堆分配,c++,performance,memory,stack,heap,C++,Performance,Memory,Stack,Heap,这个问题听起来可能相当简单,但这是我与另一位与我一起工作的开发人员进行的辩论 我在尽可能地将东西堆叠分配,而不是堆分配。他跟我说话,在我身后看着我,并评论说这是没有必要的,因为他们的表现是一样的 我一直认为,增加堆栈的时间是恒定的,堆分配的性能取决于当前堆在分配(找到适当大小的洞)和取消分配方面的复杂性(折叠孔以减少碎片,因为如果我没有弄错的话,许多标准库实现在删除过程中都会花费时间) 这对我来说可能是非常依赖于编译器的。尤其是对于这个项目,我使用的是架构编译器。了解这种组合将非常有帮助,但一般
这对我来说可能是非常依赖于编译器的。尤其是对于这个项目,我使用的是架构编译器。了解这种组合将非常有帮助,但一般来说,对于GCC和MSVC++,情况如何?堆分配的性能是否不如堆栈分配高?是否没有区别?或者差异如此微小,以至于变成了毫无意义的微观优化。您可以为特定大小的对象编写一个性能非常好的特殊堆分配器。但是,通用堆分配器的性能并不特别好
另外,我同意Torbjörn Gylle的观点,这会带来对象的预期寿命。这一点很好!您可以为特定大小的对象编写一个性能非常好的特殊堆分配器。但是,通用堆分配器的性能并不是特别好
我也同意Torbjörn Gylle的观点,这会带来对象的预期寿命。好的一点!堆栈分配要快得多,因为它真正做的就是移动堆栈指针。 使用内存池,您可以从堆分配中获得相当的性能,但这会稍微增加复杂性并带来一些麻烦
此外,堆栈与堆不仅是性能方面的考虑因素;它还告诉您许多有关对象的预期生存期的信息。堆栈分配要快得多,因为它真正做的就是移动堆栈指针。 使用内存池,您可以从堆分配中获得相当的性能,但这会稍微增加复杂性并带来一些麻烦
此外,堆栈与堆不仅是性能方面的考虑因素;它还告诉您许多有关对象的预期生存期的信息。我认为堆栈分配和堆分配通常是不可交换的。我还希望这两种分配的性能足以供一般使用 我强烈建议使用较小的项目,无论哪个项目更适合分配范围。对于较大的项目,堆可能是必要的 在具有多个线程的32位操作系统上,堆栈通常相当有限(尽管通常至少为几mb),因为需要划分地址空间,并且迟早一个线程堆栈会运行到另一个线程堆栈。在单线程系统上(无论如何,Linux glibc单线程)限制要小得多,因为堆栈可以不断增长
在64位操作系统上,有足够的地址空间使线程堆栈相当大。我不认为堆栈分配和堆分配通常是可交换的。我还希望它们的性能足以用于一般用途 我强烈建议使用较小的项目,无论哪个项目更适合分配范围。对于较大的项目,堆可能是必要的 在具有多个线程的32位操作系统上,堆栈通常相当有限(尽管通常至少为几mb),因为需要划分地址空间,并且迟早一个线程堆栈会运行到另一个线程堆栈。在单线程系统上(无论如何,Linux glibc单线程)限制要小得多,因为堆栈可以不断增长
在64位操作系统上,有足够的地址空间使线程堆栈相当大。堆栈速度更快。在大多数架构上,它实际上只使用一条指令,在大多数情况下,例如在x86上:
sub esp, 0x10
(将堆栈指针向下移动0x10字节,从而“分配”这些字节供变量使用。)
当然,堆栈的大小是非常非常有限的,因为如果您过度使用堆栈分配或尝试执行递归,您会很快发现:-)
此外,没有什么理由优化不需要验证的代码的性能,例如通过分析来演示。“过早优化”通常会导致更多的问题
我的经验法则是:如果我知道我在编译时需要一些数据,而数据的大小不到几百字节,我就堆栈分配它。否则我将堆分配它。堆栈速度快得多。实际上,它在大多数体系结构上只使用一条指令,在大多数情况下,例如在x86上:
sub esp, 0x10
(将堆栈指针向下移动0x10字节,从而“分配”这些字节供变量使用。)
当然,堆栈的大小是非常非常有限的,因为如果您过度使用堆栈分配或尝试执行递归,您会很快发现:-)
此外,没有什么理由优化不需要验证的代码的性能,例如通过分析来演示。“过早优化”通常会导致更多的问题
我的经验法则是:如果我知道我在编译时需要一些数据,而数据的大小不到几百字节,我就堆栈分配它。否则我将堆分配它。通常堆栈分配只是从堆栈指针寄存器中减去。这比搜索堆快很多 有时,堆栈分配需要添加一页或多页虚拟内存。添加一个新的零内存页并不需要从磁盘读取一个页,所以通常这仍然比搜索堆快很多(特别是
#include <cstdio>
#include <chrono>
namespace {
void on_stack()
{
int i;
}
void on_heap()
{
int* i = new int;
delete i;
}
}
int main()
{
auto begin = std::chrono::system_clock::now();
for (int i = 0; i < 1000000000; ++i)
on_stack();
auto end = std::chrono::system_clock::now();
std::printf("on_stack took %f seconds\n", std::chrono::duration<double>(end - begin).count());
begin = std::chrono::system_clock::now();
for (int i = 0; i < 1000000000; ++i)
on_heap();
end = std::chrono::system_clock::now();
std::printf("on_heap took %f seconds\n", std::chrono::duration<double>(end - begin).count());
return 0;
}
on_stack took 2.070003 seconds
on_heap took 57.980081 seconds
on_stack took 0.000000 seconds
on_heap took 51.608723 seconds
on_stack took 0.000003 seconds
on_heap took 0.000002 seconds
Proc P
{
pointer x;
Proc S
{
pointer y;
y = allocate_some_data();
x = y;
}
}
int f(int i)
{
if (i > 0)
{
int array[1000];
}
}
__Z1fi:
Leh_func_begin1:
pushq %rbp
Ltmp0:
movq %rsp, %rbp
Ltmp1:
subq $**3880**, %rsp <--- here we have the array allocated, even the if doesn't excited.
Ltmp2:
movl %edi, -4(%rbp)
movl -8(%rbp), %eax
addq $3880, %rsp
popq %rbp
ret
Leh_func_end1:
class Foo {
public:
Foo(int a) {
}
}
int func() {
int a1, a2;
std::cin >> a1;
std::cin >> a2;
Foo f1(a1);
__asm push a1;
__asm lea ecx, [this];
__asm call Foo::Foo(int);
Foo* f2 = new Foo(a2);
__asm push sizeof(Foo);
__asm call operator new;//there's a lot instruction here(depends on system)
__asm push a2;
__asm call Foo::Foo(int);
delete f2;
}