ra() is the thing that merges contiguous free blocks? Anyways, would it be worthwhile, when freeing a block, to check if there is an adjacent free block to merge with (before or after)?
This would imply keeping freed blocks in sorted lists, which (because sorting can be expensive) would in turn imply keeping multiple sorted lists (each order of magnitude larger being sorted with an order of magnitude longer interval and merging in the shorter lists at that time), and having the check walk through each of those lists. (Perhaps a pre-allocated space for holding the list of those sorted lists.) Er... unless there's some other constraint that makes this proposal be nonsense? Thanks, -- Raul On Thu, Jan 12, 2017 at 6:03 PM, Henry Rich <henryhr...@gmail.com> wrote: > Here's a little implementation info: > > 'Garbage collection' in one sense means collecting contiguous free blocks > into one large free block. This is performed only at the end of executing a > named entity. The memory allocator makes a check whenever a block is freed, > to see if garbage collection should be executed at the end of the next named > verb. > > What gc3() is doing is freeing the blocks that are no longer active. Every > time a block is allocated its death warrant is filled out & put onto the > 'tpush stack'. When the routine that allocated the block exits, every block > that the routine allocated is freed (actually, its usecount is decremented > so that if it has been assigned, it won't be freed while the assignment is > active). gc3() is used by primitives that call for lots of work by other > primitives: such a primitive must check from time to time to clear the tpush > stack lest too much accumulate. Since the primitive isn't actually > finished, there may be some blocks it has allocated that shouldn't be freed: > these are the arguments to gc3(). gc3() raises their usecounts to protect > them, processes the tpush stack, and then puts the protected arguments back > onto the tpush stack so that they will be freed when the routine ends. > > So there are lots of possible responses to this problem: > * gc3() less often > * use some other criterion, like amount of memory activity, to trigger the > call to gc3() > * Make the ra() calls in gc3(), which are expensive for boxed arguments, > run faster > * implement gc3() in a way that obviates the need for ra() > > Henry Rich > > On 1/12/2017 4:25 PM, Raul Miller wrote: >> >> I think issues might be (a) we don't know how much memory is being >> allocated in each iteration, and (b) memory allocation time might be >> an awkward spot for a garbage collect. >> >> That said, logically speaking, we want to reclaim memory when we have >> a lot of unused space. And that tends to mean after a lot has been >> allocated. >> >> So, anyways, it should be the case that we're tracking how much memory >> has been added and we attempt to reclaim after we've added a lot. >> >> (There's a potential exception here when we're right at the threshold, >> but that issue will tend to cause performance to take a dive, and it >> can become really difficult to interrupt J at that point - I'm not >> sure there's any good approach for that situation. Probably worth >> neglecting initially but eventually we'll have to deal with resource >> thresholds. On a related note, the current jbrk implementation tends >> to lead first to states where you have to reboot the machine to regain >> control and then after that to being reluctant to experiment with J. >> Personally, I'd prefer if jqt had jbrk functionality built it (with >> the dreaded 'are you sure'). But this tangent is getting way too far >> off topic now...) >> >> Anyways, there's no perfect solutions but maybe we can do better. >> >> Thanks, >> > > ---------------------------------------------------------------------- > For information about J forums see http://www.jsoftware.com/forums.htm ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm