6 ms·
Memory 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
by gizmo686 2y ago
Memory 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'.
- seabrookmx 2y agoEven when the syntax does require indentation ("with" in python, "using" in C#) it's still pretty clean IMO.
- david_allison 2y agoAdditionally, `using` no longer requires indentation in C# https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/using https://learn.microsoft.com/en-us/dotnet/csharp/language-ref...
- seabrookmx 2y agoTIL! I just recently updated a few small services to C# 12 and there's a bunch of little niceties like this I'm finding (spread operator for instance).
- pjmlp 2y agoUsing also no longer requires inheritance from IDispose, it suffices that the type does support Dispose pattern, which is great when coupled with extension methods.
- HideousKojima 2y agoUsing no longer requires a new scope block in more recent versions of C#
- valicord 2y agoThis misses the main benefit of RAII which is that you can't forget to close the file.
- pjmlp 2y agoWhile not perfect, static analysis takes care of that, in similar veins C and C++ devs reach out to them for the language flaws.
- neonsunset 2y agoDo they? // Disposed when goes out of scope using var http = new HttpClient(); var text = await http.GetStringAsync("https://example.org/");
- pjmlp 2y agoThey surely do, D for example. Swift as another one, RC is a GC algorithm, before the usual clueless reply from people not educated in CS. Followed by FP languages now adopting effects and linear type systems, alongside their automatic memory management approaches.
- mattpallissard 2y ago> you will very likely go an entire project without running into a single memory bug Sure, you haven't lost the handle to the memory, but you can still "leak" memory with a GC. Happens all the time. Add to data structure at state 1, do something in state 2, remove data in state 3. What happens you never hit state 3? > But for most programs, those modern garbage collectors are good enough that those downsides just don't matter. I mostly agree with this. Although, most programs hit a point where you have to be aware what the GC is doing and try to avoid additional allocations. Which isn't very ergonomic at times. And is often more fucking around than manual memory management, just concentrated to a smaller portion of the code base.
- oivey 2y agoAre you calling just allocating memory you’ll never use leaking? It is not. It is recoverable because for it not to be GC’d it has to be someone accessible. A memory leak means you lost the pointer to the memory, so now you can’t free it.
- gpderetta 2y ago> A memory leak means you lost the pointer to the memory, so now you can’t free it. that's an useless definition as otherwise it would be trivial to augment, say, malloc to prevent memory leaks. I would define a leak as unused memory that it is not otherwise reusable by a program.
- arccy 2y agolost can include you don't know where to find it even though you know it exists...
- Maxatar 2y ago>Are you calling just allocating memory you’ll never use leaking? It is not. Yes it is, by definition a memory leak is any memory that has been reserved but won't be read from or written to. If you allocate memory into a data structure and after some point in time you will never read from or write to that memory, then that memory constitutes a leak.
- Jasper_ 2y agoUncollectable reference cycles are shockingly easy to make in JS, especially with React. A classic example: function closure() { var smallObject = 3; var largeObject = Array(1000000); function longLived() { return smallObject; } function shortLived() { return largeObject; } shortLived(); return longLived; } Will keep largeObject alive.
- kevingadd 2y agoJS runtimes are allowed to optimize this out, IIRC, and will often do so.
- cobbal 2y agoIs this a property of JavaScript or the engine running it? This feels like something a sufficiently-smart™ closure implementation should be able to prevent.
- Jasper_ 2y agoThis is an artifact of V8's GC. Effectively, largeObject and smallObject are tracked together, as a unit. Splitting it out into two separate records increases average memory usage. They keep saying they want to fix it eventually, but it's been this way for 10+ years at this point. You really do have to know the quirks of what you're targeting.
- Dylan16807 2y ago> sufficiently-smart™ Well, the reference lua implementation handles this case fine, and it's a solid but not at all smart™ codebase.
- AgentME 2y agoThis isn't an uncollectable reference cycle. It's true that with this code in most/all JS engines, if there's a reference to the function `longLived` then `largeObject` will be kept in memory, but reference cycles are collectable in standard garbage collection systems. Both of the values will be garbage-collectable once no outside references to `longLived` still exist. Pure reference counting systems (Rust Rc, C++ shared_ptr, etc) are the kind of system that fail to automatically handle cycles. You could test this with your code by setting a FinalizationRegistry to log when they're both finalized, unset any outside reference to `longLived`, and then do something to force a GC (like run Node with --expose-gc and call `global.gc()`, or just allocate a big Uint8Array).
- patrick451 2y agoPerformance regression is a bug and GC has a horrific overhead in the average program. My computer is orders of magnitude faster than it was 15 years ago but it spends all of it's time wondering around in the wilderness hunting for memory to free. We could have just told it. > those modern garbage collectors are good enough that those downsides just don't matter. This is not what I see. Every I look at a profile of a program written in a GCed language, most of the time is spent in the garbage collector. I can't recall the last time I looked at a c++ profile where more than 10% of the time spent in new/delete. I have seen 100x speedups by disabling GC. You can't ship that, but it proves there is massive overhead to garbage collection.
- lomase 2y agoI also speed up a function 100 times. It was concatenatign strings inside a loop. I changed it to used StringBuilder instead. I could have disabled the GC to get the same speed up.
- macintux 2y ago> GC has a horrific overhead in the average program It doesn't have to be that way. The BEAM is designed for tiny processes, and GC is cheap.
- toast0 2y agoI love Erlang and BEAM, but the reason the GC is (mostly) cheap is because self-referential data structures are impossible, so you can have a very simple and yet still very effective GC. One heap per process also helps immensely. Also, when your process has a giant heap, the GC gets expensive. There's been lots of improvement over the years, but I used to have processes that could usually go through N messages/sec, but if they ever got a backlog, the throughput would drop, and that would tend towards more backlog and even less throughput, and pretty soon it will never catch up. That sometimes happens with other GC systems, but it never feels quite so dire.
- pjmlp 2y agoDepends pretty much on what implementation one is specifically talking about. Just like not all malloc()/free() were born equal, to the point companies did made big bucks selling specialised implementations.
- jules 2y agoThe article in question is about Ruby, which is garbage collected. It's easy to get in trouble with an interconnected object graph: you mess up and hold onto a pointer that you shouldn't be holding onto, which results in a leak.