Native Garbage Collection

Discussions on more advanced topics such as monolithic vs micro-kernels, transactional memory models, and paging vs segmentation should go here. Use this forum to expand and improve the wiki!
Post Reply
Xzyx987X
Posts: 21
Joined: Mon Apr 27, 2009 7:29 am

Native Garbage Collection

Post by Xzyx987X »

I'm writing an OS, which is designed to be 100% object oriented. That is to say, the entire OS consists of logical units that can be thought of as something like instances of C++ classes. Because references to objects would get passed around quite a bit in this design, making manual memory management problematic, I think it would make a lot of sense to support garbage collection for the entire system at the Kernel level.

I was looking at Wikipedia's article on garbage collection, where it talks about "Tri-colour marking":
Wikipedia wrote:Because of these pitfalls, most modern tracing garbage collectors implement some variant of the tri-colour marking abstraction, but simple collectors (such as the mark-and-sweep collector) often do not make this abstraction explicit. Tri-colour marking works as follows:
Create initial white, grey, and black sets; these sets will be used to maintain progress during the cycle.
Initially the white set or condemned set is the set of objects that are candidates for having their memory recycled.
The black set is the set of objects that cheaply can be proven to have no references to objects in the white set; in many implementations the black set starts off empty.
The grey set is all the objects that are reachable from root references but the objects referenced by grey objects haven't been scanned yet. Grey objects are known to be reachable from the root, so cannot be garbage collected: grey objects will eventually end up in the black set. The grey state means we still need to check any objects that the object references.
The grey set is initialised to objects which are referenced directly at root level; typically all other objects are initially placed in the white set.
Objects can move from white to grey to black, never in the other direction.
Pick an object from the grey set. Blacken this object (move it to the black set), by greying all the white objects it references directly. This confirms that this object cannot be garbage collected, and also that any objects it references cannot be garbage collected.
Repeat the previous step until the grey set is empty.
When there are no more objects in the grey set, then all the objects remaining in the white set have been demonstrated not to be reachable, and the storage occupied by them can be reclaimed.

The 3 sets partition memory; every object in the system, including the root set, is in precisely one set.

The tri-colour marking algorithm preserves an important invariant:
No black object points directly to a white object.

This ensures that the white objects can be safely destroyed once the grey set is empty. (Some variations on the algorithm do not preserve the tricolour invariant but they use a modified form for which all the important properties hold.)

The tri-colour method has an important advantage: it can be performed 'on-the-fly', without halting the system for significant time periods. This is accomplished by marking objects as they are allocated and during mutation, maintaining the various sets. By monitoring the size of the sets, the system can perform garbage collection periodically, rather than as-needed. Also, the need to touch the entire working set each cycle is avoided.
I think I understand what they are saying, but there is an important case that appears to be unaccounted for. Let's say the garbage collector runs during the following code:

Code: Select all

A = B;
C = D;
//garbage collector thread starts
//at the start B and D have been allocated and are referenced by A and C respectively (no other references to these objects exist)
//A and C are accessible from the root, and are placed in the grey set
//B and D are placed in the white set, as it is not yet known if they are referenced
//A's references are checked. A is moved to the black set, and B is moved into the grey set
//garbage collector thread yields
A, C = C, A; //swap A's reference with C's
//garbage collector thread resumes
//C's references are checked and B is found. C is moved to the black set, and B stays in the grey set
//D remains in the white set
//no other references to D are found, so it is deallocated
How would one get around this issue? I can think of a few ways, but they would all require user level code to cooperate with the garbage collector. For instance you could notify the garbage collector whenever a reference to an object is assigned. But this would add significant overhead, and may potentially pose a security risk, so it's far from a viable solution.
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Re: Native Garbage Collection

Post by Colonel Kernel »

Xzyx987X wrote:How would one get around this issue? I can think of a few ways, but they would all require user level code to cooperate with the garbage collector. For instance you could notify the garbage collector whenever a reference to an object is assigned.
The answer is right there in the article you quoted:
Wikipedia wrote: The tri-colour method has an important advantage: it can be performed 'on-the-fly', without halting the system for significant time periods. This is accomplished by marking objects as they are allocated and during mutation, maintaining the various sets.
Xzyx987X wrote:But this would add significant overhead, and may potentially pose a security risk, so it's far from a viable solution.
It must be viable, because it is used by many collectors, including the one Apple uses for Objective-C in OS X. There is definitely overhead though. It's a tradeoff between GC pause time and overhead while the program is running.

Note that the program code itself is not required to do anything to co-operate with the collector. Instead, write barriers are inserted to track assignments. This is done by the compiler for the OS X collector AFAIK.
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
User avatar
NickJohnson
Member
Member
Posts: 1249
Joined: Tue Mar 24, 2009 8:11 pm
Location: Sunnyvale, California

Re: Native Garbage Collection

Post by NickJohnson »

If I were you, I would probably take a look at ocaml's garbage collection system: apparently even with garbage collection, it can rival C in execution speed, although based on this article that may be partly from the combination of immutable (functional) objects and garbage collection. The standard implementation is open source IIRC, so it may prove useful as a reference implementation.
Xzyx987X
Posts: 21
Joined: Mon Apr 27, 2009 7:29 am

Re: Native Garbage Collection

Post by Xzyx987X »

Colonel Kernel wrote:It must be viable, because it is used by many collectors, including the one Apple uses for Objective-C in OS X. There is definitely overhead though. It's a tradeoff between GC pause time and overhead while the program is running.

Note that the program code itself is not required to do anything to co-operate with the collector. Instead, write barriers are inserted to track assignments. This is done by the compiler for the OS X collector AFAIK.
But how could this actually be implemented in a reasonably efficient manner? The only thing I can think of, is by having all references actually point to a table of addresses where the actual objects are. You could then set it up so writes to that table triggered a page miss during garbage collection, which could be tracked. Page misses are of course expensive, but if garbage collection is only running about 1% of the time, it's not so bad. However, now you are talking doubling memory access for anything having to do with reference assignment. Is there really no better way? Well, it could be worse I guess...
NickJohnson wrote:If I were you, I would probably take a look at ocaml's garbage collection system: apparently even with garbage collection, it can rival C in execution speed, although based on this article that may be partly from the combination of immutable (functional) objects and garbage collection. The standard implementation is open source IIRC, so it may prove useful as a reference implementation.
I doubt I'd be able to reuse any of their code, as my system is... let's call it unconventional. :wink: But I definitely have a look at it and see if there's anything I can do with it.
Xzyx987X
Posts: 21
Joined: Mon Apr 27, 2009 7:29 am

Re: Native Garbage Collection

Post by Xzyx987X »

berkus wrote:I hope your OS is not intended to do any real-time work.
Why not? If the garbage collector is running 1% of the time (and in practice I'll probably also try to work memory defragmentation into that 1% as well), it still leaves 99% of the time for everything else. On a multi-core machine the loss of speed would likely be completely irrelevant. And 1% runtime is a conservative estimation. I may be able to do with considerably less.
User avatar
NickJohnson
Member
Member
Posts: 1249
Joined: Tue Mar 24, 2009 8:11 pm
Location: Sunnyvale, California

Re: Native Garbage Collection

Post by NickJohnson »

You could also have the garbage collector run only when the processor is idle or when it is not running any real time tasks. Assuming the garbage collector could be preempted, that would make it perfectly suitable for real-time stuff, also assuming you have the free memory to delay deallocation that much.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: Native Garbage Collection

Post by Solar »

Xzyx987X wrote:
berkus wrote:I hope your OS is not intended to do any real-time work.
Why not? If the garbage collector is running 1% of the time (and in practice I'll probably also try to work memory defragmentation into that 1% as well), it still leaves 99% of the time for everything else.
"Real-time" does not mean "really fast". It means that an event can be deterministically guaranteed to be handled within a contracted time frame. That time frame might actually be rather slow, but the event must be served within it.

Imagine the computer driving the control rods in a nuclear reactor. From the moment something triggers a SCRAM event to the moment the control rods are inserted, no more than x milliseconds may pass. No matter if your OS is currently running the garbage collector or not, or if the system has triggered every possible other event at the same time. You promised x milliseconds, you have to serve within x milliseconds. That is what "real-time" is about.
Every good solution is obvious once you've found it.
Xzyx987X
Posts: 21
Joined: Mon Apr 27, 2009 7:29 am

Re: Native Garbage Collection

Post by Xzyx987X »

Solar wrote:"Real-time" does not mean "really fast". It means that an event can be deterministically guaranteed to be handled within a contracted time frame. That time frame might actually be rather slow, but the event must be served within it.

Imagine the computer driving the control rods in a nuclear reactor. From the moment something triggers a SCRAM event to the moment the control rods are inserted, no more than x milliseconds may pass. No matter if your OS is currently running the garbage collector or not, or if the system has triggered every possible other event at the same time. You promised x milliseconds, you have to serve within x milliseconds. That is what "real-time" is about.
I'm aware. I just didn't want to be pedantic about making the distinction because the statement makes sense either way (in both the sense of being immediately responsive to the user and in the sense of allowing for strict timing of scheduled events). As long as the garbage collector is also being scheduled in real time, you can still make guarantees about execution time windows. You can also preempt the garbage collector if needed. It makes things a bit more complicated, but if you're talking 1% execution time for the garbage collector, servicing real time requests should not be an issue.
Post Reply