9 ms·
I just dont understand the fear with manual memory management. With RAII and and simple diligance (clear ownership rules), managing memory is an easy engineerin
by smallstepforman 2y ago
I just dont understand the fear with manual memory management. With RAII and and simple diligance (clear ownership rules), managing memory is an easy engineering task. I actually find it *more* challenging to deal with frameworks that insist or reference counting and shared pointers since ownership is now obscure.
I create it, I free it. I transfer, I no longer care. Its part of engineering discipline. Memory bugs are no worse than logic bugs, we fix the logic bugs, makes sense to fix the memory bugs. Disclaimer: I do embedded complex systems that run 24/7.
We do the same for OS resources (handles, sockets, etc) and dont use automatic resource managers, we do it manually. So why complicate the design with automatic memory management?
- yosefk 2y ago35% of vulnerabilities in the biggest tech companies being due to use after free bugs are a part of the answer. (More than 90% of severe vulnerabilities are due to memory bugs impossible in memory-safe languages.)
- samatman 2y agoEvery memory-safe language has a runtime written in a memory-managed language. Yes, even Rust: Rust is implemented using many (well-vetted) unsafe blocks. So projects to improve the quality, and lower the defect rate, in memory-managed programming, are far from wasted. Even if they only get used to write fast garbage collectors so that line coders can get on with the work of delivering value to customers.
- loeg 2y agoManual memory management vs GC is orthogonal to memory safe vs unsafe.
- AgentME 2y agoIn practice the lines of each issue are placed very close together. Other than Rust, there are no popular memory safe languages that use manual memory management.
- mrkeen 2y ago> We do the same for OS resources (handles, sockets, etc) and dont use automatic resource managers 1) Modern languages have made inroads here. 2) The OS is my automatic resource manager. When I hit ctrl-c on my running C program, my free() is never hit, yet it is cleaned up for me. > So why complicate the design with automatic memory management? I don't know beforehand who is going to be reading my memory, how many times, in what order, or whether they're going to copy out of it, or hold onto pointers into it. > I just dont understand the fear with manual memory management. With RAII and and simple diligance (clear ownership rules), managing memory is an easy engineering task. I claim that if managing memory is that straightforward, then it makes more sense to leave it to the compiler (Rust-style, not Java-style.) rather than let a human risk messing it up.
- jeremyjh 2y agoMemory leaks can be hard to track down, but overflows and use after free bugs can take a project weeks off schedule. Depending on what is overwritten and where, the effects show up very far from the source of the problem. For an engineering or product manager this is a terrifying prospect. Managed memory more or less solves those problems - it introduces a couple of others and there are still a possibility of resource leaks but these problems are both more rare and generally easier to pin down.
- n4r9 2y ago> Memory bugs are no worse than logic bugs I guess it comes down to what you mean by "worse". It seems that memory bugs carry a higher risk of being completely invisible except in deliberately contrived situations. This makes them more dangerous because there's less of an incentive to fix something that clients will never notice.
- _gabe_ 2y ago> It seems that memory bugs carry a higher risk of being completely invisible except in deliberately contrived situations. Do they really carry a higher risk of being invisible though? You don’t need to “contrive” situations either. My company just spent 6+ months trying to solve a JavaScript undefined symbol bug stemming from a library. When we finally tracked it down, it was because we were using import instead of require, which the documentation didn’t clarify was important. The fix we implemented was nowhere near where we expected the bug, and the only reason we finally solved it was because we had exhausted all other options. Sounds the same, if not worse, as a difficult to track memory bug to me.
- n4r9 2y agoI'm not sure if I get your point here, but it's possible that "invisible" was too ambiguous. What I meant was that a memory bug may be less likely to cause noticeable functional changes to the behaviour of the program during everyday usage. I.e. the client won't notice them.
- elondaits 2y agoI worked with manual memory management for a decade (24/7 systems) and don’t miss it. It’s not per-se hard, it’s not scary, but if you’re dealing with structures that may contain reference loops, or using an architecture based on event handlers that may be moving references around, you need to do some very careful design around memory management instead of just thinking of the problem domain.
- hedora 2y agoBy far, the worst memory leak I’ve ever had to debug involved a cycle like you are describing, but it was in a Java program (swing encourages/encouraged such leaks, and “memory leaks in java are impossible”, so there weren’t decent heap profilers at the time). For the last few decades, I’ve been writing c/c++/rust code, and the tooling there makes it trivial to find such things. One good approach is to use a C++ custom allocator (that wraps a standard allocator) that gets a reference to a call site specific counter (or type specific counter) at compile time. When an object is allocated it increments the counter. When deleted, it decrements. Every few minutes, it logs the top 100 allocation sites, sorted by object count or memory usage. At process exit, return an error code if any counters are non-zero. With that, people can’t check in memory leaks that are encountered by tests. In practice, the overhead of such a thing is too low to be measured, so it can be on all the time. That lets it find leaks that only occur in customer environments.
- billjings 2y agoBut circular references don't leak in Java. You have to have a GC root (e.g. a static, or something in your runtime) somewhere pointing at the thing to actually leak it. There is one case where a "circular" reference can appear to cause a leak that I know of: WeakHashMap. But that's because the keys, which are indeed cleaned up at some point once the associated value is GC'd, are themselves strongly retained references.
- chopin 2y agoThreadLocal can be another problem. Tomcat kills and recreates threads for this reason. Edit: another one is swapping code by swapping class loaders. That can retain static references in the runtime class loader.
- pylua 2y agoBusinesses need software to be less complex and easier to develop so it is cheaper. I can’t imagine manual memory management on these large scale projects with a high variance of developer scale and opinions.
- watermelon0 2y ago> We do the same for OS resources (handles, sockets, etc) and dont use automatic resource managers, we do it manually. Generally, in most languages, file handles and sockets are automatically closed, when the variable holding them gets out of scope.
- inetknght 2y ago> just dont understand the fear with manual memory management. With RAII and and simple diligance (clear ownership rules), managing memory is an easy engineering task. I actually find it more* challenging to deal with frameworks that insist or reference counting and shared pointers since ownership is now obscure.* I mostly agree. With RAII, memory management is simplified. "Just" evaluate the lifetime of the object. Super easy if you're good at software design. Reference counting and shared pointers still have their niche use case. But I've most often seen referencing counting used as a crutch where reference-counting is _easy_ but designing around object lifetimes is more appropriate. > Memory bugs are no worse than logic bugs It's true. A memory bug is "just" another logic bug. Memory bugs lead to null pointers and wild pointers. They're just as dangerous as logic bugs. Memory bugs are also far more preventable with RAII. > We do the same for OS resources (handles, sockets, etc) and dont use automatic resource managers, we do it manually. So why complicate the design with automatic memory management? I'm just going to point out that I don't do manual allocations for OS resources. I wrap OS resources into RAII objects. I've made lots (!) of custom RAII wrappers for OS objects and library objects. It's trivial to do and saves a feckton of headaches. C++ has std::fstream. I'm not saying it's great. But it's definitely RAII for files and has been around for... well I don't know exactly but certainly 25+ years.
- xedrac 2y agoRAII was a huge improvement over C and I was shocked to see Zig forego such an improvement. Rust adopted RAII, and took it all to the next level with no data races and a lot more bugs caught at compile time.
- pjmlp 2y agoRust helped making affine types acceptable in mainstream. The next level is going into linear types, which is what some GC first languages are now slowly looking into.
- gizmo686 2y agoMemory bugs is an entire class of bugs that we have simply solved. If you use a language with a modern garbage collector (e.g. one that can handle cycles), you will very likely go an entire project without running into a single memory bug. To a first approximation, these bugs were not replaced with other bugs; they are simply gone. Further, we do not ask anything more of the programmer do accomplish this. Instead, we need the programmer to do less work than they would need to do with manual memory management. That is not to say that garbage collection is an unambigous win. There are real downsides to using it. But for most programs, those modern garbage collectors are good enough that those downsides just don't matter.
- barbariangrunge 2y agoEven game engines (including unreal) use gc these days, which is nuts. Still though, it’s best to be careful with your allocations, use pooling, etc
- im3w1l 2y agoThere is one downside, though it's not inherent to garbage collection, it just happens to correlate in current languages. Gc'd languages don't have raii, and for that reason they actually make you do more work when managing non-memory resources. The have been some attempts to work around this with e.g. pythons with, but In my opinion it's less ergonomic due to forcing indentation.
- vbezhenar 2y agoGo's defer works like RAII and does not introduce indentations. f := createFile("/tmp/defer.txt") defer closeFile(f) writeFile(f)
- rcxdude 2y agoDefer and context managers are a pale approximation of RAII. They are constrained to lexical scope, as opposed to RAII which works with object lifetimes. And it's the latter case which is much more error prone than 'oops, I forgot to close a file I opened this function'.
- deleted 2y ago[deleted]
- armchairhacker 2y agoIMO it’s not that memory management is hard, it’s that developers are imperfect, so writing a 100% UB-free, leak-free program is hard. And it only takes a single oversight to cause havoc, be it a CVE, leak that causes a long-running program to slowly grow memory, or hair-pulling bug that occurs 1 in 1000 times. Yes, logic bugs have the same issues, and even in languages like Java we can sometimes (albeit rarely IIRC) get memory leaks. But memory-safe languages are an improvement. Just like TypeScript is an improvement over JavaScript, even though they have the same semantics. We have automated systems that can decrease the amount of memory errors from 1% to 0.01%, why keep leak and UB prevention a manual concern? Moreover, the drawbacks of memory-safe languages are often not an issue: you can use a GC-based language like Java which is easy but has overhead, or an enforced-ownership language like Rust which has a learning curve but no overhead. Meanwhile, while logic bugs can be a PITA, memory bugs are particularly notorious, since they don’t give you a clear error message or in some cases even cause your program to halt when they occur. Tangential: another solution that practically eliminated a class of bugs is formal verification. And currently we don’t see it in any system but those where correctness is most important, but that’s because unlike memory management the downsides are very large (extremely verbose, tricky code that must be structured a certain way or it’s even more verbose and tricky). But if formal verification gets better I believe that will also start to become more mainstream.
- jandrewrogers 2y agoThe use of manual memory management increases the cognitive load when reasoning about software. Working memory capacity varies considerably between people and is a performance limiting factor when designing complex systems. You see analogues of this in other engineering disciplines too. Over my many years of working in software development I have come around to the idea that most software developers do not have sufficient working memory capacity to reason about memory management in addition to everything else they must reason about at the same time. They may know mechanically how to properly do manual memory management but when writing code they drop things if they are juggling too many things at once mentally. It isn't a matter of effort, there simply is a complexity threshold past which something has to give. Automatic memory management has its tradeoffs but it also enables some people to be effective who otherwise would not be. On the other side of that you have the minority that get manual memory management right every time almost effortlessly, who don't grok why it is so difficult for everyone else because it is literally easy for them. I think some people can't imagine that such a group of engineers exist because they are not in that group and their brain doesn't work that way. If you are in this group, automatic memory management will seem to make things worse for unclear benefit. I've observed this bifurcation in systems software my entire career. In discussions about memory safety and memory management, it is often erroneously assumed that the latter population simply doesn't exist.
- mattpallissard 2y agoI think the rift comes from people thinking manual memory management is a bunch of random allocs and frees all over the place. That is gross and those of us who don't mind managing memory don't like it either. Personally my gripe is when people don't think about memory or space complexity at all. I don't care if it's a custom memory management strategy or GC'd language, you need to think about it. I have the same gripe about persistence, socket programming, and database queries. Abstractions are great, use them, love them. But understanding what the hell they are doing under the hood not only improves efficiency, it prevents bugs, and gives you a really solid base when reasoning about unexpected behavior.
- danielledias204 2y ago
- artemonster 2y agoOh yes! And also dont forget about the hand holding static type system that wont let you fart unless you explicitly convince it that you will not shit your pants!
- bigstrat2003 2y agoIf manually managing memory were in fact an easy engineering task, software developers wouldn't be so demonstrably bad at it.
- derriz 2y agoSure, for simple flows-of-control, GC buys you little and an RAII type approach is fine. But RAII really only works if lifecycle and ownership spans are reflected in the lexical structure of the code base. RAII relies on creation and cleanup happening within a block/lexical scope. Unfortunately in the real C++ codebases I've had to work with, the flow of control is never so simple. Any correspondence between lexical scope and lifecycle is broken if the code uses exceptions, callbacks, any type of async, threads, etc.
- tlarkworthy 2y ago... or a persistent data-structure [1]. [1] https://en.wikipedia.org/wiki/Persistent_data_structure https://en.wikipedia.org/wiki/Persistent_data_structure
- pixelfarmer 2y agoNo, it still applies. You have to think on a higher abstraction level, like components with interfaces between them of sorts. If one of them creates a resource (because this goes far beyond memory allocations which are also only resources), it MUST take care to delete that resource again. Whether that happens in a different thread or whatever: Who cares. (And yes, more care needs to be taken around creation/deletion/use of resources then.) The Linux kernel is loaded with examples of it. Any deviation from that MUST be documented which includes seeing that as comments in code so people who read/maintain that code know what this is all about. Thing is, many memory leaks are actually logic bugs and no (resource-)GC will save your bacon against these, in fact, you made your life more complicated through it because now you have to debug through another (abstraction) layer before getting to the true problem. This is what this ownership in Rust is all about: It makes ownership visible to the programmer so they have to take care about it in a very explicit manner.
- pjmlp 2y agoIt doesn't scale in large teams of various skill levels.
- tracer4201 2y ago[dead]
- kelnos 2y agoSo you never, ever, ever make a mistake? No, don't bother answering that. Of course you do. No amount of "engineering discipline" in the world can stamp out the human propensity to occasionally make a mistake.
- Brian_K_White 2y agoWhere did they say that? Why do you jump to that? Why didn't you assume that they make errors like everyone, and simply deal with them? Your ego is so fragile that it can't survive un the the same universe with the idea that someone somewhere might be living just fine without a crutch you apparently consider indispensable? The fact is there are more than one way to detect and avoid errors reaching all the way to production. Every other human activity since humans existed employs them for thousands of years before golang existed. Rigor and discipline and methodology are not actually impossible. Shock!
- anon-3988 2y agoYou can literally replace memory management in your post with stack management. You wouldn't say the same thing about stack push and pop would you? Memory management is kind of a solved problem for 99% of program. It only happens very rarely and under very constrained environment. Yes, I did encountered a stack overflow error because I didn't realize the size of the struct is gigantic. So I solved it by creating the object on the heap instead. Similarly, memory "bugs" in managed systems is very rare and they can mostly be solved. Every time a managed systems have issues, we get blog posts like this exactly because they are rare. If I write a blog post every time I have encountered a memory leak in a C program, well no one really cares. It's kind of expected.
- klysm 2y agoHistory has repeatedly demonstrated that it is not easy. Simple diligence is clearly insufficient.