4 ms·
You can’t do it that way because each object has to have its own lifetime. If you allocate them all as a single allocation, then the entire allocation would be
by coder543 5y ago
You can’t do it that way because each object has to have its own lifetime.
If you allocate them all as a single allocation, then the entire allocation would be required to live as long as the longest lived object. This would be horribly inefficient because you couldn’t collect garbage effectively at all. Memory usage would grow by a lot, as all local variables are continuously leaked for arbitrarily long periods of time whenever you return a single one, or store a single one in an array, or anything that could extend the life of any local variable beyond the current function.
If you return a stack variable, it gets copied into the stack frame of the caller, which is what allows the stack frame to be deallocated as a whole. That’s not how heap allocations work, and adding a ton of complexity to heap allocations to avoid using the stack just seems like an idea fraught with problems.
If you know at compile time that they all should be deallocated at the end of the function… the compiler should just use the stack. That’s what it is for. (The one exception is objects that are too large to comfortably fit on the stack without causing a stack overflow.)
- chrisseaton 5y ago> If you allocate them all as a single allocation, then the entire allocation would be required to live as long as the longest lived object. No, you can copy objects out if they live longer than others. That's how a generational GC works.
- coder543 5y agoI edited my comment before you posted yours. Making heap allocations super complicated just to avoid the stack is a confusing idea. Generational GCs surely do not do a single bump allocate for all local variables. How could the GC possibly know where each object starts and ends if it did it as a single allocation? Instead, it treats them all as individual allocations within an allocation buffer, which means bumping for each one separately. Yes, they will then get copied out if they survive long enough, but that’s not the same thing as avoiding the 10+ instructions per allocation. It’s entirely possible I’m wrong when it comes to Truffle, but at a minimum it seems like you would need arenas for each size class, and then you’d have to bump each arena by the number of local variables of that size class. The stack can do better than that.
- chrisseaton 5y agoWhen you allocate objects individually it looks like this: object_a = tlab tlab += 8 check tlab limit object_b = tlab tlab += 8 check tlab limit When you allocate as a single allocation it looks like this: object_a = tlab object_b = tlab + 8 tlab += 16 check tlab limit What about that do you see as impossible? > How could the GC possibly know where each object starts and ends if it did it as a single allocation? As above.
- deleted 5y ago[deleted]
- coder543 5y agoIn your example, the objects are all the same size. That would certainly be easy. If you have three local objects that are 8 bytes, 16 bytes, and 32 bytes… if you do a single 48 byte allocation on the TLAB, how can the GC possibly know that there are three distinct objects, when it comes time to collect the garbage? I can think of a few ways to kind of make it work in a single buffer, but they would all require more than the 48 bytes that the objects themselves need. Separate TLAB arenas per size class seem like the best approach, but it would still require three allocations because each object is a different size. I understand you’re some researcher related to Truffle… this is just the first I’m hearing of multiple object allocation being done in a single block with GC expected to do something useful.
- chrisseaton 5y ago> If you have three local objects that are 8 bytes, 16 bytes, and 32 bytes… if you do a single 48 byte allocation on the TLAB, how can the GC possibly know that there are three distinct objects, when it comes time to collect the garbage? Because the objects are self-describing - they have a class which tells you their size. object_a = tlab object_a.class = ClassA object_b = tlab + 8 object_b.class = ClassB object_c = tlab + 16 object_c.class = ClassC tlab += 48 check tlab limit
- 5y ago