What programming languages does support VLAs?

Started by
25 comments, last by SmkViper 8 years, 3 months ago


Because in such cases they are created faster then calling for example 'malloc'.

There's nothing to stop you pre-malloc'ing a large block of memory, and then using a stack (FIFO) allocator to allocate smaller arrays from that block. You've now amortised the cost of a single malloc call across all array allocations, and it's likely just as fast as using VLAs, since it too behaves like a stack.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Advertisement


Another thing is as you probably know newer 64bit processors have a lot more registers then 32bit ones so I'm sure that even using more then a single VLA can be optimized and work faster then 'heap'.

What does having more registers have to do with anything?

-potential energy is easily made kinetic-

And besides 'C++' too. I already knew that one.

C++ actually doesn't support them as a language feature. It's an area where C99 and C++03 actually diverged from each other.

I use them in C++ by implementing my own scopes and stacks that are separate from the language's default call-stack and block scopes.

Clever idea. So i take it you just have a special 'stack allocator' that really uses the heap but works like a stack under the hood?


There's nothing to stop you pre-malloc'ing a large block of memory, and then using a stack (FIFO) allocator to allocate smaller arrays from that block. You've now amortised the cost of a single malloc call across all array allocations, and it's likely just as fast as using VLAs, since it too behaves like a stack.

Except it might not be thread safe and you might not have a suitable way to identify which thread you are on or be able to pass a thread local pool/heap-stack/whatever along. An example is a callback from a library, that might be called from multiple threads. In my case, it was an OS callback that was fired on (among others) malloc() and free(). The options were VLAs or always worst case.

So i take it you just have a special 'stack allocator' that really uses the heap but works like a stack under the hood?

Pretty much. I try to avoid all globals in my current engine, which includes "the heap", as it obviously is a global data structure. I create quite a few different stacks (and pools, and heaps) for different purposes. The Dice scope stack allocation presentation gives a good idea on how to implement this while retaining C++ niceties such as RAII and constructors/the object model.

Back in the PS2/Wii era, we actually pre-allocated all the RAM and then split it up by geographical regions in the game world! e.g. we'd have 3 "level chunk" sized buffers, each of which had a "cursor" for stack allocations. When streaming in a new chunk of a game level, we'd pre-create all the objects possibly required within that chunk's stack. This let us have 2 chunks loaded at a time, and a 3rd one streaming in / being constructed. If you needed temporary / per-frame memory, you could record the cursor, allocate some more objects on the stack, and then reset the cursor back to your 'recorded' value to 'erase' them. When unloading a chunk of the world, we'd just reset it's cursor to the beginning of it's buffer, to indicate all those objects were gone. This was back in the "C with classes" style of C++, so we didn't simply call destructors, etc... and had custom shutdown logic where required.

In my case, it was an OS callback that was fired on (among others) malloc() and free(). The options were VLAs or always worst case

Change Swift's quote to start with "In most cases, " then wink.png


Except it might not be thread safe and you might not have a suitable way to identify which thread you are on or be able to pass a thread local pool/heap-stack/whatever along. An example is a callback from a library, that might be called from multiple threads. In my case, it was an OS callback that was fired on (among others) malloc() and free(). The options were VLAs or always worst case.

So use a stack allocator per thread. That's what you are doing by using VLAs, anyway, since each thread has its own stack.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

So use a stack allocator per thread. That's what you are doing by using VLAs, anyway, since each thread has its own stack.


Not sure what you mean here? (honest question)

Are you talking about a pre-allocated (on heap) pool with stack like semantics? How could I do that without passing anything along to my function? Some compiler extension which allows per-thread globals?

Or are you talking about a stack-allocated buffer on each thread? Either we'd have to allocate it early on and pass it along, or we'd have to create the buffer each time we enter the function, but how would that be better than using a fixed-size array of worst case size?

Or are you talking about using some macro/whatever to manipulate the stack pointers explicitly? Would this be better than using compiler supported VLAs in some way? (again, honest question)

So use a stack allocator per thread. That's what you are doing by using VLAs, anyway, since each thread has its own stack.


Not sure what you mean here? (honest question)

Are you talking about a pre-allocated (on heap) pool with stack like semantics? How could I do that without passing anything along to my function? Some compiler extension which allows per-thread globals?


You can use thread-local storage which is supported by most compilers, and as of C++11 is part of the standard.

You can also pretty easily determine what pool a pointer came from simply by address. Each pool knows its starting address, and its size, so if your pointer address is between the starting address and the starting address + size, then it belongs to that pool, and that pool can deallocate it. If you then need to deallocate from a different thread you can then either use locks to manipulate said pool immediately, or post a message to that thread to tell it to deallocate said pointer itself later on.

And since you're allocating from the heap, you can make the pools as big as you want, rather than being limited to stack size.

Of course, a stack allocator will quickly have fragmentation issues, so it is best to use one for either short-lived allocations or very long-lived ones. (Unless you want to get into the fun topic of compacting heaps ;) )

This topic is closed to new replies.

Advertisement