“the ultimate in garbage collection” had me almost fall out of my chair. Memory management in embedded systems truly increases entropy in the universe.
> paying a software engineer to fix a memory leak: $x,xxx,xxx
Paying the software engineer would be a fraction of the cost to fix the memory leak in software. Recertification of the software would blow it all away.
Serious question: adding more / different memory wouldn't also trigger recertification of the software?
It seems like those shouldn't be coupled, but I seem to remember (horror) stories about programs running on machines with segmented memory, where the segments straddled each other, and/or where the last segment wrapped around to the beginning of RAM. Expanding RAM in such a scenario would cause wrapped writes to no longer wrap, for example.
Or any other illogical reason a program could use or abuse the size of RAM for. It just never ceases to amaze me how things that should be completely decoupled can end up not being.
Man, I hope so. Do you know how many times I've seen "really simple" one-line changes hose everything? Bonus points if they're to fix something that was pressing but not urgent and now you've just made it 10x worse.
Let me put it this way, if there is a car that doesn’t get its driving software recertified even after one line of code is changed, you do not want that car.
One of the anecdotes I keep in my back pocket about how anything can be funded by the military was a compilers professor whose research on real-time Java was funded by the military. Apparently some drone control software was written in Java, and having your drone use stop-the-world garbage collection is bad in a number of ways.
It's certainly a humorous anecdote and arguably a practical solution to the problem.
But when the mission of the code expands beyond the original use case, this element might be lost. It's best to encode these limitations/constraints into the design of the program, whenever possible. However for this case I cannot imagine how to do that. When that's impossible, it's ideal to advertise these limitations as a design feature coupled with the intended use cases. Therein lies the only hope of discovering this before it causes problems.
These days, the vast, vast majority of our code can and should undergo unit testing and have sanitizer tests enabled for that unit testing. We should be extremely cautious about whitelisting/bypassing those checks (but at least those are more explicit signals).
I thought I remember reading this story in the past but it also talked to the real time requirements and there wasn't enough time to free the memory. Not sure if I am making this up or not though. Either way, it is a factor that cannot be ignored
That's humorous but sad in so many ways. Regarding the original quote - if I see a malloc for a bunch of memory intended for the lifetime of the app and it's at the beginning of main and then it doesn't get freed before the end of process execution it's not really a memory leak in my book. Still, I wouldn't write code like that.
A variant of that I've seen in many small 1990s C apps is create a huge struct with all the program data in it, with fixed size arrays of things big enough so that's all you ever need, and just declare one global struct.
It was one struct instead of separate globals because of some coding style guide at the time.
"But what if we want to use this in a library?"
"Here's all the data in one container, malloc it and use that."
I don't think many of those programs ever did end up in libraries.
The original yacc(1) was written with fixed-size arrays for the parser tables, statically allocated. If the parser was too complex, the arrays would blow. To fix that, change the DEFINEs and recompile yacc.
> if I see a malloc for a bunch of memory intended for the
> lifetime of the app and it's at the beginning of main and
> then it doesn't get freed before the end of process
> execution it's not really a memory leak in my book.
Not freeing such memory and otherwise not explicitly destroying all your state can hide bugs, hide legitimate leaks, and add noise to memory profilers like valgrind. Destroying your state exercises those code pathways, which is very valuable.
Plus, it's just a good habit in a language with manual memory management. It's like wearing your seatbelt--if it's a habit you just do it as a matter of course without thought, no matter whether you're driving around the block or across the country. You start making exceptions, you break the habit, you invite errors of judgment.
Yes, the reasons you mention are why I would always free pre-malloced memory.
However, a real memory leak, to me, is memory that gets allocated at different times through the lifetime of the app and doesn't get reliably freed do to unexpected code paths or race conditions. If I don't see the allocation count rise steadily while I run my app I'm not as worried.
I remember this kind of approach being proposed for a game debugging tool, and for writing games in a managed language. Basically, everything you wanted to keep or consider permanent was marked or kept in one part of the heap, and everything that was allocated to execute a frame was implicitly thrown away. (One way to do it would be to compact the heap before starting the frame, then use the top of the heap as a barrier.)
I also saw this strategy used in coursework. I was in graduate school, and I had just done the Compiler class the previous semester. My best friends were taking the course, and the professor had concocted a home made leak checker and foisted it on the class, declaring that no program with leaks would be accepted for the final project. It was only a few weeks before the end of the term, and everyone was demoralized. Jokingly, I suggested that everyone just make their own mechanism of the same kind, which would track allocations then release all of the program's allocated memory just before the prof's leak checker ran. As it turns out, the whole class ended up implementing my idea. The test data was small enough, that everyone's compilers could afford to simply leak memory, then release it all at the end. Problem solved.
33 comments
[ 3.1 ms ] story [ 88.9 ms ] threadadding memory: $xxx per missile paying a software engineer to fix a memory leak: $x,xxx,xxx
Paying the software engineer would be a fraction of the cost to fix the memory leak in software. Recertification of the software would blow it all away.
It seems like those shouldn't be coupled, but I seem to remember (horror) stories about programs running on machines with segmented memory, where the segments straddled each other, and/or where the last segment wrapped around to the beginning of RAM. Expanding RAM in such a scenario would cause wrapped writes to no longer wrap, for example.
Or any other illogical reason a program could use or abuse the size of RAM for. It just never ceases to amaze me how things that should be completely decoupled can end up not being.
> blow it all away
I appreciated the wording there. :)
This makes me wonder, will self-driving cars need recertification if even one line of code is touched?
But when the mission of the code expands beyond the original use case, this element might be lost. It's best to encode these limitations/constraints into the design of the program, whenever possible. However for this case I cannot imagine how to do that. When that's impossible, it's ideal to advertise these limitations as a design feature coupled with the intended use cases. Therein lies the only hope of discovering this before it causes problems.
These days, the vast, vast majority of our code can and should undergo unit testing and have sanitizer tests enabled for that unit testing. We should be extremely cautious about whitelisting/bypassing those checks (but at least those are more explicit signals).
It was one struct instead of separate globals because of some coding style guide at the time.
"But what if we want to use this in a library?" "Here's all the data in one container, malloc it and use that."
I don't think many of those programs ever did end up in libraries.
Plus, it's just a good habit in a language with manual memory management. It's like wearing your seatbelt--if it's a habit you just do it as a matter of course without thought, no matter whether you're driving around the block or across the country. You start making exceptions, you break the habit, you invite errors of judgment.
However, a real memory leak, to me, is memory that gets allocated at different times through the lifetime of the app and doesn't get reliably freed do to unexpected code paths or race conditions. If I don't see the allocation count rise steadily while I run my app I'm not as worried.
Missing (1995) on the title, and perhaps a [Usenet] tag?
I concur. I've heard this story a number of times, and it smells like a myth.
Well, maybe terrain recognition navigation system might need to allocate memory. Or perhaps a data link for processing commands. But probably not.
Funny, though.
I also saw this strategy used in coursework. I was in graduate school, and I had just done the Compiler class the previous semester. My best friends were taking the course, and the professor had concocted a home made leak checker and foisted it on the class, declaring that no program with leaks would be accepted for the final project. It was only a few weeks before the end of the term, and everyone was demoralized. Jokingly, I suggested that everyone just make their own mechanism of the same kind, which would track allocations then release all of the program's allocated memory just before the prof's leak checker ran. As it turns out, the whole class ended up implementing my idea. The test data was small enough, that everyone's compilers could afford to simply leak memory, then release it all at the end. Problem solved.
In fact, it's entire flight time could be a few seconds. Imagine an air-to-air missile fired by an aircraft at another aircraft.
I don't think the project ever got anywhere, but back then, your KDE desktop spent a good 15-30 seconds carefully deallocating all objects.