• Quick note - the problem with Youtube videos not embedding on the forum appears to have been fixed, thanks to ZiprHead. If you do still see problems let me know.

Software quality collapse

Sometimes the simplest solution is to periodically restart the process. And by simplest I mean best.

Laypersons and romantics, fed by academic idealism and Hollywood fantasies, imagine that there is an elegant solution for every problem. That a serious programmer will always avoid memory leaks through elite haxxoring.

But sometimes the serious programmer is the one who tells the customer to reboot the server every Saturday at 1am, and goes back to sleep.
 
Last edited:
I started out in assembler, then moved to C. Eventually, I had to use C++, too. Most of my programs these days are still a mix of C and C++, although I've used more modern languages for web stuff. Other than in testbeds, I've never had a dangling allocation or null/invalid pointer. If you do it right, those things don't happen.
 
Sometimes the simplest solution is to periodically restart the process. And by simplest I mean best.

Laypersons and romantics, fed by academic idealism and Hollywood fantasies, imagine that there is an elegant solution for every problem. That a serious programmer will always avoid memory leaks through elite haxxoring.

But sometimes the serious programmer is the one who tells the customer to reboot the server every Saturday at 1am, and goes back to sleep.
I have, I have been told, done that without waking up. When on call for a major bank applications on the mainframes would fail because badly trained programmers don't write god error handlers. My phone would ring, I'd answer, listen "Restart the app and send a ticket to my team". In the morning I'd count the tickets ad fill in the overtime. Yes I got on-call pay plus a minimum of 2 hours OT an time I got called.
One of the 2 most common errors (the other being SQL timeout due to lock escalation) was apps overwriting storage. COBOL programmers who barely understood COBOL never mind the runtime environment. The code ran in IBM's LE Language Environment "enclaves" (a sort of container) and allocated memory would have begin and end markers. Loops would ask for enough to handle n elements and then handle n+1 overwriting the end market and frequently another apps memory. It wasn't even "off by 1" errors.
 
I just now saw this thread.


In the 1990s and early 2000s, several researchers sought to quantify the real-world overhead of using garbage collection (which is usually what people mean by "memory-managed") instead of manual deallocation. I was one of them.

That research was hard to publish, mainly because the experimental results usually showed manual deallocation to be less advantageous than conventional wisdom expected. It wasn't at all unusual for garbage collection to perform better than manual deallocation. You couldn't get that kind of result published.
I find that surprising. The conventional wisdom in my small part of the IT world was that garbage collection is faster. For example, allocation under GC is very simple. You have a big wodge of contiguous memory and you just take a slice off one end for your new object. With manual memory management, you typically have lists of free blocks of memory that have to be manipulated. There are other overheads too on deallocation, plus subtle things like keeping things together for better cache performance.

Of course, with a garbage collector, a lot of this work still has to happen but it's deferred until some condition triggers a collection. You may then get slow downs for brief periods but these are unlikely to be a serious problem for most general purpose systems.
 
...plus subtle things like keeping things together for better cache performance.
This is huge for us in our embedded applications. Some of our code relies on reasonably predictable cache performance.

Of course, with a garbage collector, a lot of this work still has to happen but it's deferred until some condition triggers a collection. You may then get slow downs for brief periods but these are unlikely to be a serious problem for most general purpose systems.
And this is huge for us in our supercomputer applications. We may have literally a thousand CPUs executing SIMD code whose program steps want to end at as close to the same instant as possible. The way it works, it will have to work at the speed of the slowest node. So if the process on one CPU decides to collect garbage, the entire supercomputer has to stop and wait for that to happen.

Other than that, we use a lot of Python for less specialized purposes, and we don't care when or how much it garbage-collects or how long it takes.
 
I find that surprising. The conventional wisdom in my small part of the IT world was that garbage collection is faster. For example, allocation under GC is very simple. You have a big wodge of contiguous memory and you just take a slice off one end for your new object. With manual memory management, you typically have lists of free blocks of memory that have to be manipulated. There are other overheads too on deallocation, plus subtle things like keeping things together for better cache performance.

Of course, with a garbage collector, a lot of this work still has to happen but it's deferred until some condition triggers a collection. You may then get slow downs for brief periods but these are unlikely to be a serious problem for most general purpose systems.
In my experience at the time, precise garbage collection was almost always faster than manual deallocation. On the other hand, few programmers of that time used or cared about precise garbage collection. What they cared about was the performance of languages such as C and C++, which (due to their design) are unable to use precise garbage collection. Most empirical studies of that time therefore compared manual deallocation to the conservative (hence not precise) garbage collectors that were available for C and C++.

For his master's thesis, one of my PhD students constructed an implementation of Scheme that could use any of several different garbage collectors (including conservative, generational precise, and stop-and-copy precise), and used it to compare their performance on a number of allocation-intensive benchmarks. The conservative collector was competitive on some benchmarks, but often not competitive at all. For his PhD dissertation, he (and I) designed, implemented, and benchmarked two new algorithms for precise generational collection, comparing their performance to the more traditional precise generational and stop-and-copy collectors. I don't think he bothered to benchmark against the conservative collector, but I'd have to check on that before I could be sure.

Another PhD student implemented and tested another novel gc algorithm, which is scalable in the sense of guaranteeing bounded latency regardless of data size and program behavior. We then published a couple of conference papers about that algorithm and its refinements, but the real-time gc world was (and continues to be) far more interested in algorithms that have to be fine-tuned for particular applications than in a general-purpose algorithm whose guaranteed latency is independent of the application program. Which goes some way toward explaining why we were never able to get the funding needed to build an industrial-quality implementation of our algorithm.

By the way, that second PhD student (Felix Klock) served as senior lead of the Rust compiler team until 2023 and continues to contribute to the evolution of Rust's design.
 
Last edited:
...
The other reason is that the standard allocation and deallocation libraries used by C and C++ were adequately efficient for programs that didn't do much allocation and deallocation, but quite slow when stressed by the allocation-intensive programs where you can hope to see measurable differences between manual deallocation and garbage collection. The research I described above motivated those who maintained those libraries to rewrite them. The rewritten libraries used today are much more efficient than the libraries used back then.
Usual solution to such problem area is to use memory pools. (Boost has one such sets of implementations) I think that would erase any GC advantage.

That programming style is considered poor in C and C++ because those languages do not use and cannot use modern garbage collectors; they are limited to smart pointers and/or conservative garbage collection. In languages that are designed for precise garbage collection, with implementations that use modern garbage collectors, that programming style is not only acceptable but quite efficient.
It should be noted that official support for GC in C++ has been depreciated.
 

Back
Top Bottom