> > So you're saying that the calls to get memory during interpreter
> > initialization are somehow guaranteed to not require more memory (and thus
> > a dod or collection run)? Currently, this guarantee is not expressed in
>
> I don't understand the "thus."  Nothing states that requesting memory
> mandates a DOD/GC run.

If I call Parrot_allocate, it checks to see if it has enough allocated
memory to provide the request. If not, it performs a collection run, and
tries again. If not, it tries allocationg a new block of memory, and
returns that. If that fails, it gives up.

So if our initial allocation size for some reason isn't enough for all of
the parrot initializations, it will cause a collection run. This in turn
depends that the various *_pools were correctly initialized. If this is
not the case (say, we're allocating memory for the pools in the first
place), bad things happen.

Likewise, the construction of a new PMC for the stash_hash could cause a
DOD to occur if there aren't enough PMC headers available. Granted one
won't cause this, or even a few. But the possibility exists, if say the
stash_hash PMC initializes a bunch of default PMCs for its use, or
somesuch.

> > code, comments, or documentation, from what I can tell. And I personally
> > hate implicit assumptions like these...they're the cause of all that magic
> > voodo, far away from where it's obvious what the problem is. We have no
> > idea of knowing how much is 'enough' for the GC to allocate at startup,
> > aside from the following the code and tracking allocations, which can be
> > a pain.
>
> I guess it depends on what you consider to be initialization.  Little, if
> any, of what the interpreter itself demands in memory - including memory for
> the GC itself - is going to be reclaimable; it's all mostly persistent
> throughout the life of the interpreter.

Right. However, that's not to say that memory cannot grow. The interpreter
allocates the various *_pools from the interpreter's memory_pool, and it
gets copied with each collection run. This memory can grow and change in
size as more memory for pools are needed. Currently, we use the GC's
buffer system for tha. Alternately, we could use mem_sys_allocate, and
manually free and allocate memory for them. The latter would then allow
these pools to not be copied during collection runs, and would eliminate
that particular element of unsafety.

> If there's not enough memory to bootstrap the interpreter and the GC, then
> even if the GC *could* reclaim enough to satisfy subsequent requests,
> there's not going to be nearly enough memory left to do anything.  So why
> bother?

Because if there's not enough memory, it can still allocate *more* memory.
It just tries to reclaim enough memory before resorting to the 'extreme'
of getting more system memory. I hope that makes things clear.

> (Just) enough of the interpreter needs to start up to start up the memory
> allocator and the GC subsystem.  If it needs more memory to do so, it should
> simply be given more memory.  After the GC is up and running, the
> interpreter/bootstrapping process can trigger a GC run to free up as much
> memory as it can.  The remainder of the interpreter can then start up,
> running through the GC.

You're, right, it should be given more memory to do so. But since it
performs a collection run before getting more memory, and since it's not
safe to perform a collection run during initialization, bad things happen.

Mike Lambert


Reply via email to