On Tue, May 15, 2012 at 12:34 PM, Raoul Duke <[email protected]> wrote:
> On Tue, May 15, 2012 at 12:23 PM, Jonathan S. Shapiro <[email protected]> > wrote: > > These are known as unboxed types. Automatic stack allocation is a good > > thing, but it should be done generally. What you need to do this is > escape > > analysis, which is *not* a simple inference problem in the general case. > > Conservative escape analysis is often good enough in practice. > > as an offshoot of looking for something like BitC, thinking about what > might be "good enough" for doing e.g. games, i think i would like to > have more manual controls over the GC and less magic like escape > analysis that i have to rely on... Hang on there. I didn't say that automatic stack allocation should be the only mechanism. In fact, I've argued very strongly elsewhere that relying exclusively on automatic stack allocation for critical system software is completely unacceptable. Eike said that he contemplated a simple scheme for stack allocating certain kinds of structures: closures and dictionaries. It turns out that one of his two examples - closures - is actually not so easy to unbox automatically because of the need for escape analysis. Once he has to do escape analysis, he should consider automatic stack allocation more generally. But note that all of this is completely invisible at the source level; it doesn't impact the externally visible semantics, and therefore can be deferred for later implementation. Concerning manual controls over GC: I understand why you *want* manual control over GC. Unfortunately, the price is something you won't be willing to pay. The price of manual GC control is the requirement that the application tolerate out of memory exceptions as a routine case inside critical algorithms. For this and several other reasons, I would argue that what you should really be seeking is the ability to write allocation-free critical code. And yes, I know that isn't possible in all cases, and I'm aware of the work on region-structured memory management. The problem with the region-structured approach is that the usual implementation doesn't address fragmentation concerns, and there are cases where regions don't get collected eagerly enough - notably due to loops. Today's hack is tomorrow's backwards compatibility nightmare. The lower you go in the software stack, the bigger the impact of a compatibility nightmare is. Language design sits *very* low in the functional stack. Tread carefully. e.g. random > thought, being able to say "please check to see if you can gc any of > the things that were heap allocated during this function call" could > be nice. There are three possible implementations: 1. Implement it by performing a full GC of new-space (in which case you should just call that) 2. Implement it by region analysis, discarding the function-local region. In practice this may not turn out to release any storage [see below]. 3. Implement it by escape analysis and aggressive stack allocation. This approach works, but it has a cost [see below]. In order to understand why "discard by region" isn't attractive, we need to take note that the goal is less about releasing current storage than it is about being able to allocate new objects from the storage that we release. A consequence of this is that discarding a region isn't useful unless it happens to fall at the very end of the heap, which is something that is very difficult to ensure. If it *doesn't* fall at the end of the heap, then you can't unwind the next-allocation pointer, and you won't be able to actually reclaim that space until the next generational GC (which would have reclaimed it anyway). The alternative is to do some stack-like region management strategy that is *separate* from the heap so that it doesn't interfere. You don't want to do this on the actual stack. The problem is that a FOR loop can cause a lot of allocations from region R in each pass, most of which become garbage in the next pass. It's not that hard to end up in a state where you are forced to GC the region, which is just what you were trying to avoid. The aggressive stack allocation approach works, because it allocates storage from a place that doesn't interfere with GC (that is: from the stack). It requires that all of the stack-allocated storage be non-escaping - and particularly that it not escape into other threads of control. The hidden "gotcha" is that it causes stack frames to grow, which makes incremental and/or concurrent collection harder. I won't pretend to understand all of the region-related issues here. As I wrote the argument above, it occurred to me that it should be possible to identify per-region "roots", and thereby to perform small compacting collections on a region by region basis. The "small" part makes the collections relatively fast. The compacting is necessary in order for re-allocation to work properly. shap
_______________________________________________ bitc-dev mailing list [email protected] http://www.coyotos.org/mailman/listinfo/bitc-dev
