我正在研究一个玩具编译器。 我曾经使用 malloc 分配所有内存,但由于我从不调用 free,我认为在堆栈上分配大约 GB 左右然后慢慢使用该缓冲区就足够了(而且更快)。
但。。。现在我正在发生任何有趣的事情之前进行分段错误。 它发生在我大约 30% 的测试用例上(本节中的所有测试用例都相同)。 从 GDB 粘贴:
(gdb) disas
Dump of assembler code for function main:
0x0000000000400bf1 <+0>: push rbp
0x0000000000400bf2 <+1>: mov rbp,rsp
0x0000000000400bf5 <+4>: mov QWORD PTR [rip+0x2014a4],rsp # 0x6020a0
0x0000000000400bfc <+11>: sub rsp,0x7735940
0x0000000000400c03 <+18>: sub rsp,0x7735940
0x0000000000400c0a <+25>: sub rsp,0x7735940
0x0000000000400c11 <+32>: sub rsp,0x7735940
=> 0x0000000000400c18 <+39>: call 0x400fec <new_Main>
0x0000000000400c1d <+44>: mov r15,rax
0x0000000000400c20 <+47>: mov rax,r15
0x0000000000400c23 <+50>: add rax,0x20
0x0000000000400c27 <+54>: mov rax,QWORD PTR [rax]
0x0000000000400c2a <+57>: add rax,0x48
0x0000000000400c2e <+61>: mov rax,QWORD PTR [rax]
0x0000000000400c31 <+64>: call rax
0x0000000000400c33 <+66>: mov rax,0x0
0x0000000000400c3a <+73>: mov rsp,rbp
0x0000000000400c3d <+76>: pop rbp
0x0000000000400c3e <+77>: ret
我最初做了一个大的"sub rsp,0x...",我认为分解它会有所帮助(它没有 - 程序在调用时崩溃)。 在这种情况下,总数应为 500MB。
真正让我感到困惑的是为什么它在"呼叫<>"而不是其中一个订阅器上失败。 以及为什么它只是在某些时候失败,而不是总是或永远不会失败。
披露:这是一个学校项目,但寻求有关 x86 的一般问题的帮助并不违反任何规则。
更新:根据@swift的评论,我设置了 ulimit -s 无限...它现在随机出现段错误? 这似乎是随机的。 它并没有接近使用整个 500 MB 缓冲区。 它总共只分配大约 400 个字节。
从RSP
中减去某些内容不会引起任何问题,因为没有人使用它。它只是一个带有值的寄存器,它不分配任何东西。但是,当您使用CALL
时,将访问RSP
指向的内存,并且可能会出现问题。堆栈通常不是很大,所以对于您的问题"是否有任何理由不能从堆栈中获取 GB 内存",答案是"因为堆栈没有那么多空间可供使用"。
至于更快地在堆栈中分配一个大的缓冲区并不是一回事。在堆中分配和释放单个大内存块的速度并不慢。堆中有大量分配和发布比堆栈中更糟糕。因此,在这种情况下,在堆栈中执行此操作没有多大意义。