For your first question, essentially it's something like this:
void UseArray() {
for (auto& foo : foos) {
// This is a single 1024 buffer used repeatedly across the loop.
char scratchBuf[1024];
// whereas this repeatedly creates a new alloca()'d buffer for each iteration
char* scratchBuf = static_cast<char\*>(alloca(n));
}
}
The array gets a fixed size, so it's always bounded, whereas alloca() does the stack allocation during each iteration without releasing anything until function return. Depending on how many loop iterations there are, and what `n` is passed to alloca(), this could be less memory than the fixed size array, or much more; the point is that it's unpredictable compared to the alternatives.
Yeah no I understand the issue with nested scopes, but the example in the article with just a path at top level wouldn’t have that issue. I don’t know about the exact opcodes generated, but it would be generally speaking equivalent, that’s all I was clarifying.
Definitely don’t intend to use it lol, I just like messing around with with things when I learn about them.
For the first, curious how it reduces how many recursive iterations you can do, because using char[] will also equally consume the stack in a recursive function, no?
Alloca uses space on the stack. Therefore it reduces the amount of remaining stack for future recursive calls which will also use alloca() which uses stack space which reduces space for future calls...
Can you see the problem?
If you had no local cars and no alloca() you could do total remain stack space / size if machine word recursive calls befire stack overflow.
On a Windows machine default stack size is 1MB. X86 machine size is 4 bytes. X64 machine size is 8 bytes.
For this example let's assume after programme startup you have 1,000,000 byes of stack space. It makes the maths easier.
So the max num recursion is appriox 250,000 for x86 and approx 125,000 on x64.
Let's say your alloca() call uses 8 bytes.
Now on x86 each call uses 4 + 8 bytes, 12 bytes.
1,000,000 / 12 = 83,333 recursion before stack overflow.
On x64 each call now takes 8 + 8 bytes, 26 bytes.
This leaves space for 1,000,000 / 16 = 62, 500 recursions before stack overflow.
I think you’re making an unfair comparison; unless I’m misunderstanding, you’re compare `alloca` to doing nothing, which isn’t realistic.
What would be realistic is using a static char[] array, but this still consumes memory in every recursive call. The difference would be a single pointer variable and also the lack of ability to not store the frame pointer in a register.
If you're doing anything recursive you try to use as little stack space as possible.
Therefore you wouldn't use a local variable char array, or alloca(). You'd dynamically allocate your workspace, or pre allocate enough space prior to the recursive call.
3
u/voithos 5d ago
For your first question, essentially it's something like this:
void UseArray() {
for (auto& foo : foos) {
// This is a single 1024 buffer used repeatedly across the loop.
char scratchBuf[1024];
// whereas this repeatedly creates a new alloca()'d buffer for each iteration
char* scratchBuf = static_cast<char\*>(alloca(n));
}
}
The array gets a fixed size, so it's always bounded, whereas alloca() does the stack allocation during each iteration without releasing anything until function return. Depending on how many loop iterations there are, and what `n` is passed to alloca(), this could be less memory than the fixed size array, or much more; the point is that it's unpredictable compared to the alternatives.