Hacker News new | ask | show | jobs
by simias 2311 days ago
I think it's a bad mindset to leak resources even when it doesn't effectively matter. In non-garbage collected languages especially, because it's important to keep in mind who owns what and for how long. It also makes refactoring easier because leaked resources effectively become some sort of implicit global state you need to keep track of. If a function that was originally called only once at startup is not called repeatedly and it turns out that it leaks some memory every time you know have a problem.

In this case I assume that a massive amount of testing mitigates these issues however.

5 comments

I think you are conflating two issues: while one should understand who owns what and for how long, it does not follow that one should always free resources even when it is not necessary, if doing so adds complexity and therefore more things to go wrong, or if it makes things slower than optimal.

In this particular case, correctness was not primarily assured by a massive amount of testing (though that may have been done), but by a rigorous static analysis.

Freeing memory also isn't free - the bookkeeping necessary, both at allocation and at free time and potentially also for the allocating code has costs.

In postgres memory contexts are used extensively to manage allocations. And in quite few places we intentionally don't do individual frees, but reset the context as a whole (freeing the memory). Obviously only where the total amount of memory is limited...

I feel like I've read about some rocket launch failures that were caused in part by launch delays leading to overflow and sign flipping, but can't find it now =/

It may be unwise to overide static analysis (a leak is found) with hueristics (the program won't run long enough to matter)

It is not just a heuristic if you have hard upper bounds on the things that matter - in that case, it is static analysis. A missile has a limited, and well-defined, fuel supply.

In the case of memory management, it is not enough to just free it after use; you need to ensure that you have sufficient contiguous memory for each allocation. If you decide to go with a memory-compaction scheme, you have to be sure it never introduces excessive latency. It seems quite possible that to guarantee a reallocation scheme always works, you have to do more analysis than you would for a no-reallocation scheme with more memory available.

This depends entirely on the mode of operation which I suspect neither of us know in great detail; if in any circumstance the runtime of the program is not tied to expenditure of fuel you have literal ticking time bomb.

Ideally we'd be able to tie such assertions into a unified static analysis tool, rather than having humans evaluate conflicting analyses. And god forbid the hardware parameters ever change, because now you need to re-evaluate every such decision, even the ones nobody documented. Case in point: Arianne 5 (not exactly my original scenario, but exactly this one -- 64bit -> 16 bit overflow caused a variety of downstream effects ending in mission failure).

Well, yes, I already explained that it depended on circumstances, and just let me add that I would bet the engineer quoted in the article (explaining that the memory leaks were a non-issue) knew much more about the specifics than either of us.

The Ariane 5 issue is not, of course, a memory leak or other rescource-release-and-reuse issue. It is a cautionary tale about assumptions (such as the article's authors assumption that memory leaks are always bad.)

In a perfect world, yes. But in a hard real time system (and much of missile control will likely be designed as such), timing may be the #1 focus. That is, making sure that events are handled in at most X microseconds or N CPU cycles. In such cases adding GC may open a new can of worms.

I agree that in general leaking resources is bad, but sometimes it is good enough by a large margin. Just a guess.

It would be an acceptable solution if the memory supply would vastly outsize the demand, by over an order of magnitude. For example if the program never needed more than 100MiB and you'd install 1GiB or 10GiB. 10GiB is still nothing compared to the cost of the missile, and you get the benefit of truly never worrying about the memory management latency.

My favorite trick to optimizing some systems is to see if I can mlock() all of the data in RAM. As long as it's below 1TiB it's a no brainer - 1TiB is very cheap, much cheaper than engineer salaries that would otherwise be wasted on optimizing some database indices.

What’s your rationale for picking an order of magnitude instead of, say, double?
10x is a very safe margin. I suppose 2x is fine if you really know your code (usually you don't, really, unless you wrote all of it yourself).
Well, I’m not sure I’d call buying 1TiB of RAM and mlock’ing it all an optimization.
It is not an "optimization" in the sense that it's not engineer's work.

It is in the sense that it gets the speedup job done.

Double is an order of magnitude.
I suppose it is, in binary. Although humans generally use base 10.

I might have to start saying "a binary order of magnitude" instead of "double" when circumstances call for gobbledygook.

there are always constraints. other than the cost of the memory, which may appear minimal, there are many others. for a missile that bigger memory chip may require more current, more current means a bigger power supply, or a thicker wire. might add ounces to the weight. and in this environment, that may be significant (probably not in this specific example, but look at this perspective for every part selected...they sum up)
> As long as it's below 1TiB it's a no brainer - 1TiB is very cheap, much cheaper than engineer salaries that would otherwise be wasted on optimizing some database indices.

Until you have ten thousand machines in your cluster…

I meant 1TiB total.
One TB of memory is actually quite expensive. And uses a fair bit of power.
Not at all compared to salaries.

I mean just think about how many VMs you can buy for $200k-$500k/yr (total cost to the company of a senior engineer).

According to AWS you could only afford 10 instances each with 976GB of RAM for that salary (500k). If you were to do nothing but just buy the raw RAM it would cost you 50k. But you also need servers [0] to actually put the ram into. So it's probably closer to 70k. RAM isn't as cheap as you think.

[0] and a network and network admins and server admins and and and

So you mean 4-10TiB is the equivalent of a senior engineer via AWS pricing and my rough estimate of the cost of an engineer. I think we agree?
Freeing memory (or running a garbage collector) has a cost associated with it, and if you are freeing memory (or closing files, sockets, etc) before exiting a program it's time wasted, since the OS will free all the resources associated with the program anyway.

And a lot of languages, and for sure newer version of the JVM, do exactly that, they don't free memory, and doesn't run the garbage collector since the available memory gets too low. And that is fine for most applications.

There are a number of old-school C programs that follow a familiar template: they're invoked on the command line, run from top to bottom, and exit.

For those, it's often the case that they allocate-only, and have a cleanup block for resources like file handles which must be cleaned up; any error longjmps there, and it runs at the end under normal circumstances.

This is basically using the operating system as the garbage collector, and it works fine.

"I gave cp more than a day to [free memory before exiting], before giving up and killing the process."

https://news.ycombinator.com/item?id=8305283

https://lists.gnu.org/archive/html/coreutils/2014-08/msg0001...