What deterministic garbage collection algorithms are out there?
Asked Answered
N

10

19

By deterministic I vaguely mean that can be used in critical real-time software like aerospace flight software. Garbage collectors (and dynamic memory allocation for that matter) are big no-no's in flight software because they are considered non-deterministic. However, I know there's ongoing research on this, so I wonder if this problem has been solved yet.

I'm also including in the question any garbage collection algorithms that put restrictions on how they're used.

Nailhead answered 20/10, 2008 at 5:10 Comment(2)
Deterministic != deterministic. A non-GC system has a deterministic time when you request for memory to be freed, but not necessarily a deterministic amount of time that it will take.Digitalin
Related question: Is malloc deterministic? (it's not).Cheddite
T
17

I know I might get a lot of down-votes for this reply, but if you are already trying to avoid dynamic memory in the first place, because you said it's a no-no, why do you use GC at all? I'd never use GC in a real-time system where predictable runtime speed is the major concern. I'd avoid dynamic memory wherever possible, thus there are very, very little dynamic objects to start with and then I'd handle the very few dynamic allocations I have manually, so I have 100% control when something is released and where it is released. After all not just GC is not deterministic, free() is as little deterministic as malloc() is. Nobody says that a free() call just has to mark the memory as free. It might as well try to combine smaller free memory blocks surrounding the free'd one to a big one and this behavior is not deterministic, nor is the runtime for it (sometimes free won't do that and malloc will do that instead on next allocation, but nowhere is written that free mustn't do that).

In a critical realtime system, you might even replace the system standard malloc()/free() with a different implementation, maybe even writing your own one (it's not as hard as it sounds! I've done that before just for the fun of it) that works most deterministic. For me GC is a plain convenience thingy, it is to get programmers away from focusing on sophisticated malloc()/free() planing and instead having the system deal with this automatically. It helps doing rapid software development and saves hours of debugging working finding and fixing memory leaks. But just like I'd never use GC within an operating system kernel, I'd never use it within a critical realtime application either.

If I need a more sophisticated memory handling, I'd maybe write my own malloc()/free() that works as desired (and most deterministic) and write my own reference counting model on top of it. Reference counting is still manual memory management, but much more comfortable than just using malloc()/free(). It is not ultra fast, but deterministic (at least increasing/decreasing the ref counter is deterministic in speed) and unless you may have circular references, it will catch all dead memory if you follow a retain/release strategy throughout your application. The only non deterministic part about is that you won't know if calling release will just decrease the ref counter or really free the object (depending if the ref count goes to zero or not), but you could delay the actual free by offering a function to say "releaseWithoutFreeing", which decreases the ref counter by one, but even if it reaches zero, it won't free() the object yet. Your malloc()/free() implementation can have a function "findDeadObjects" that searches for all objects with a retain counter of zero, that have not yet been released and free them (at a later point, when you are in a less critical part of your code that has more time for such kind of tasks). Since this is also not deterministic, you could limit the amount of time it may use for this like "findDeadObjectsForUpTo(ms)", and ms is the amount of milliseconds it may use for finding and freeing them, coming back as soon as this time quantum has been used, so you won't spent too much time in this task.

Thorium answered 21/10, 2008 at 12:17 Comment(2)
That's why I am asking. GC and dynamic memory allocation are not used because they are non-deterministic, but maybe at least with GC is a solved problem by now. I'm interested because: I want to use a functional language, and we are talking about huge real-time applicationsNailhead
@Nailhead GC and real time systems are two terms that must never appear within the same sentence. On real time systems you just don't want anything non-deterministic and already memory allocation is, and not even GC can help you with that. So first you need to kill non-deterministic alloc and when you do, there will be no need for a GC as there is nothing it could clean up.Thorium
D
10

Metronome GC and BEA JRockit are two deterministic GC implementations that I'm aware of (both for Java).

Democrat answered 20/10, 2008 at 5:34 Comment(1)
Are they actually deterministic? Neither website actually says that (although Metronome tries hard to imply it). It seems to me it would be possible to make a GC "determinitic" just by limiting the work it does at a single shot. That seems to be the approach lots of folks take. However, that means you could get into situations where you run out of memory when you should have plenty because the GC is falling behind.Chifley
H
7

Happened to be searching through Stack Overflow and noticed this rather old post.

Jon Anderson mentioned JamaicaVM. Since these posts have been up for over 4 years now, I think its important to respond to some of the information posted here.

I work for aicas, the developers and marketers of JamaicaVM, JamaicaCAR, and Veriflux.

JamaicaVM does have a hard realtime garbage collector. It is fully preemptive. The exact same behavior required in a realtime operating system. Although the preemption latency is CPU speed dependent, assume that on a Ghz class processor preemption of the garbage collector is less than 1 microsecond. There is a 32 bit singlecore version that supports up to 3 GB of memory per process address space. There is a 32 bit multicore version that supports 3 GB of memory per process address space and multiple cores. There are also 64 bit singlecore and multicore versions that support up to 128 GB of memory per process address space. The performance of the garbage collector is independent of the size of memory. In response to one of the responses regarding running the GC completely out of memory, for a hard realtime system you would not design your program to ever do that. Although you can, in fact, use a hard realtime GC in this scenario, you would have to account for a worst case execution time that probably would not be acceptable to your application.

Instead, the correct approach would be to analyze your program for maximum memory allocation, and then configure the hard realtime garbage collector to incrementally free blocks during all previous allocations so that the specific scenario described never occurs. This is known as thread-distributed, work-paced garbage collection.

Dr. Siebert's book on Hard Realtime Garbage Collectors describes how to accomplish this and presents a formal proof that the garbage collector will keep up with the application, while not becoming an O(N) operation.

It is very important to understand that realtime garbage collection means several things:

  1. The garbage collector is preemptible, just like any other operating system service
  2. It can be proven, mathematically that the garbage collector will keep up, such that memory will not be exhausted because some memory has not been reclaimed yet.
  3. The garbage collector does not fragment memory, such that as long as there is memory available, a memory request will succeed.
  4. Additionally, you will need this to be part of a system with priority inversion protection, a fixed priority thread scheduler and other features. Refer to the RTSJ for some information on this.

Although hard realtime garbage collection is needed for safety-critical applications, it can be used mission critical, and general purpose Java applications as well. There is no inherent limitations in using a hard realtime garbage collector. For general use, you can expect smoother program execution since there are no long garbage collector pauses.

Horton answered 23/6, 2012 at 23:36 Comment(0)
F
3

To me, 100% real-time Java is still very much a hit-and-miss technology, but I don't claim to be an expert.

I'd recommend reading up on these articles - Cliff Click blog. He's the architect of Azul, has pretty much coded all of the standard 1.5 Java concurrent classes etc... FYI, Azul is designed for systems which require very large heap sizes, rather than just standard RT requirements.

Flense answered 20/10, 2008 at 8:8 Comment(0)
B
2

It's not GC, but there are simple O(1) fixed sized block allocation/free schemes you can use for simple usage. For example, you can use a free list of fixed sized blocks.

struct Block {
   Block *next;
}

Block *free_list = NULL; /* you will need to populate this at start, an 
                          * easy way is to just call free on each block you 
                          * want to add */

void release(void *p) {
    if(p != NULL) {
        struct Block *b_ptr = (struct Block *)p;
        b_ptr->next = free_list;
        free_list = b_ptr;
    }
}

void *acquire() {
    void *ret = (void *)free_list;
    if(free_list != NULL) {
        free_list = free_list->next;
    }
    return ret;
}

/* call this before you use acquire/free */
void init() {
    /* example of an allocator supporting 100 blocks each 32-bytes big */
    static const int blocks = 100;
    static const int size = 32;
    static unsigned char mem[blocks * size];
    int i;
    for(i = 0; i < blocks; ++i) {
        free(&mem[i * size]);
    }
}

If you plan accordingly, you could limit your design to only a few specific sizes for dynamic allocation and have a free_list for each potential size. If you are using c++, you can implement something simple like scoped_ptr (for each size, i'd use a template param) to get simpler yet still O(1) memory management.

The only real caveat, is that you will have no protection from double frees or even accidentally passing a ptr to release which didn't come from acquire.

Banister answered 16/11, 2008 at 7:59 Comment(0)
U
2

Sun has extensively documented their real-time garbage collector, and provided benchmarks you can run for yourself here. Others mentioned Metronome, which is the other major production-grade RTGC algorithm. Many other vendors of RT JVMs have their own implementations -- see my list of vendors over here and most of them provide extensive documentation.

If your interest is particularly in avionics/flight software, I suggest you take a look at aicas, an RTSJ vendor who specifically markets to the avionics industry. Dr. Siebert's (aicas CEO) home page lists some academic publications that go into great detail about PERC's GC implementation.

Ulrich answered 10/4, 2009 at 2:42 Comment(0)
O
1

You may have some luck with the following PhD thesis CMU-CS-01-174 - Scalable Real-time Parallel Garbage Collection for Symmetric Multiprocessors.

Ormiston answered 20/10, 2008 at 8:35 Comment(0)
S
1

Real-time means a guaranteed upper bound on response time. This means an upper bound on the instructions that you can execute until you deliver the result. This also puts an upper limit on the amount of data you can touch. If you don't know how much memory you're going to need, it is extremely likely that you'll have a computation for which you cannot give an upper limit of its execution time. Otoh, if you know the upper bound of your computation, you also know how much memory gets touched by it (unless you don't really know what your software does). So, the amount of knowledge you have about your code obviates the need for a GC.

There are features, like regions in RT-Java, that allow for expressiveness beyond local and global (static) variables. But they will not relieve you from your obligation to manage the memory you allocate, because otherwise you cannot guarantee that the next upcoming allocation will not fail because of insufficient memory resources.

Admittedly: I've gotten somewhat suspicious about things that call themselves "realtime garbage collectors". Of course, any GC is real time if you assume that every allocation runs a full collection (which still doesn't guarantee that it will succeed afterwards, because all memory blocks might found to be reachable). But for any GC that promises a lower time bound on allocation, consider its performance on the following example code:

// assume that on `Link` object needs k bytes:
class Link {
    Link next = null;
    /* further fields */
    static Link head = null;
}

public static void main (String args) {
    // assume we have N bytes free now
    // set n := floor (N/k), assume that n > 1

    for (int i = 0; i < n; i ++) {
        Link tmp = new Link ();
        tmp.next = Link.head;
        Link.head = tmp;
    } 
    // (1)
    Link.head = Link.head.next; // (2)
    Link tmp = new Link ();  // (3)
}
  • At point (1), we have less than k bytes free (allocation of another Link object would fail), and all Link objects allocated so far are reachable starting from the Link.static Link head field.
  • At point (2),

    • (a) what used to be the first entry in the list is now not reachable, but
    • (b) it is still allocated, as far as the memory management part is concerned.
  • At point (3), the allocation should succeed because of (2a) - we can use what used to be the first link - but, because of (2b), we must start the GC, which will end up traversing n-1 objects, hence have a running time of O(N).

So, yes, it's a contrived example. But a GC that claims to have a bound on allocation should be able to master this example as well.

Salina answered 7/3, 2009 at 11:8 Comment(0)
H
1

I know this post is a bit dated, but I have done some interesting research and want to make sure this is updated.

Deterministic GC can be offered by Azul Systems "Zing JVM" and JRocket. Zing comes with some very interesting added features and is now "100% software based" (can run on x86 machines). It is only for Linux at this time though ...

Price: If you are on Java 6 or before Oracle is now charging a 300% uplift and forcing support for this capability ($15,000 per processor & $3,300 support). Azul, from what I have heard is around $10,000 - $12,000, but charges by physical machine, not core / processor. Also, the process are graduated by volume so the more servers you leverage the deeper the discounting. My conversations with them showed them to be quite flexible. Oracle is a perpetual license and Zing is subscription based ... but if you do the math and add in other features that Zing has (see differences below).

You can cut cost by moving to Java 7, but then incur development costs. Given Oracle's roadmap (a new release every 18 months or so), and the fact that they historically only offer the latest plus one older versions of Java SE updates for free, the "free" horizon is expected to be 3 years from the initial GA release if any major version. Since initial GA releases are typically not adopted in production for 12-18 months, and that moving production systems to new major java releases typically carries major costs, this means that Java SE support bills will start hitting somewhere between 6 and 24 months after initial deployment.

Notable differences: JRocket does still have some scalability limitations in terms of RAM (though improved from days of old). You can improve your results with a bit of tuning. Zing has engineered their algorithm to allow continuous, concurrent, compaction (no stop the world pauses and no "tuning" required). This allows Zing to scale without a theoretical memory ceiling (they are doing 300+ GB heaps without suffering stop the world or crashing). Talk about a paradigm changer (think of the implications to big data). Zing has some really cool improvements to locking giving it amazing performance with a bit of work (if tuned, can go sub-millisecond average). Finally, they have visibility into classes, methods, and thread behavior in production (no overhead). We are considering this as a huge time saver when considering updates, patches, and bug-fixes (e.g. leaks & locks). This can practically eliminate the need to recreate many of the issues in Dev / Test.

Links to JVM Data I found:

JRocket Deterministic GC

Azul Presentation - Java without Jitter

Azul / MyChannels Test

Heeheebiejeebies answered 12/12, 2012 at 17:26 Comment(0)
F
0

I know azul systems has a jvm whose GC is hardware assisted. It can also run concurrently and collect massive amounts of data pretty fast.

Not sure how deterministic it is though.

Fen answered 20/10, 2008 at 5:18 Comment(2)
Azul is not quite real-time though... Even Cliff Click, their chief-architect is careful in describing is as 'semi real time'. It's designed more for trading systems (worst case scenario = loss of $) rather than real-time physics systems (worst case scenario = loss of life).Flense
@AndrewfromNZSG I would like to make sure this is updated, Azul now has a JVM that is 100% software based and low latency capable.Heeheebiejeebies

© 2022 - 2024 — McMap. All rights reserved.