5 ms·
Coincidentally, Ada optionally supports garbage collection in its specifications but it's up to the runtime to implement it.
by ajdude 4y ago
Coincidentally, Ada optionally supports garbage collection in its specifications but it's up to the runtime to implement it.
- pjmlp 4y agoAnd since no implementation has ever supported it, it has been deprecated in ISO Ada 95 and further removed from it on ISO Ada 2012. https://en.wikibooks.org/wiki/Ada_Programming/Pragmas/Controlled https://en.wikibooks.org/wiki/Ada_Programming/Pragmas/Contro...
- admax88qqq 4y agoThere was this project though. https://github.com/Roldak/AGC https://github.com/Roldak/AGC The best part is that it's faster than manual management. People will tell you they need do to malloc and free manually for performance, but when you actually run the numbers GC wins for a majority of use cases.
- vlovich123 4y agoTracing garbage collectors don’t generally win against reference counting connectors, especially when those reference counts are automatically elided via ARC (eg swift and objective C) or because they’re rarely used by means of composition (c++ and rust). Additionally, different kinds of application strategies are better depending on the use case (eg a pool allocator that you bulk drop at the end of some computation). What papers are you referencing showing tracing GCs outperforming things? If it’s just the website, I think it’s an artifact of a micro benchmark rather than something that holds true for non trivial programs.
- kaba0 4y agoThen why do every performant managed language opts for tracing GCs when they can? RC is used in lower level languages because it doesn’t require runtime support, and can be implemented as a library. As I wrote in another comment, even with elisions, you are still trading off constant writes on the working thread for parallel work, and you even have to pay for synchronization in parallel contexts.
- adgjlsfhk1 4y agothis isn't fully true. Java is in the process of getting lxr which is uses both tracing and reference counting.
- NobleExpress 4y agoYes and no. LXR is a highly optimized deferred and coalesced reference counting (amongst many other optimizations) GC and it looks nothing like the RC implementations you see in other languages like Python, Nim, Swift, etc. So yes, reference counting can be performant, _but_ only if you are using a deferred and coalesced implementation as otherwise the simple implementation requires atomic operations for every pointer read/write operation (though compilers could optimize it to use non-atomic operations when it's sure semantics are preserved). EDIT: The post you're responding to is referring to the simple standard implementation of RC.
- vlovich123 4y agoRust doesn’t use multi threaded Rc unless you actually need to send it across threads.
- NobleExpress 4y agoI'm aware. Rust isn't a conventional "managed language" which is why I consciously omitted it from the above list. In an increasingly multi-threaded world, you just have to use the synchronized version of RC (aka Arc<T> in Rust).
- KerrAvon 4y agoBecause they don’t care as much about working set size as Apple does.
- kaba0 4y agoSure, it is a tradeoff as basically every other technical choice. But we were talking about performance here, and especially in throughput, tracing GCs are much better.
- NobleExpress 4y agoI've always heard of the "Swift elides reference counts" statements but I've never seen it substantiated. I don't claim to be a Swift GC expert by any means, but the impression I get from the two Swift GC papers I've read [1, 2] is that Swift has a very simple implementation of RC. The RC optimization document (albeit the document is incomplete) [3] also doesn't give me the impression that Swift is doing much eliding of reference counts (I'm sure it is doing it for simple cases). Do you have any links which might explain what kind of eliding Swift is doing? EDIT: The major RC optimizations I have seen which elide references are deferral and coalescing and I'm fairly certain that Swift is doing neither. [1]: https://dl.acm.org/doi/abs/10.1145/3170472.3133843 https://dl.acm.org/doi/abs/10.1145/3170472.3133843 [2]: https://doi.org/10.1145/3243176.3243195 https://doi.org/10.1145/3243176.3243195 [3]: https://github.com/apple/swift/blob/main/docs/ARCOptimization.md https://github.com/apple/swift/blob/main/docs/ARCOptimizatio...
- astrange 4y agoSwift's compiler elides obviously useless RC operations at compile time. It doesn't do anything at runtime though.
- vlovich123 4y agoThat is correct. Like Objective-C the compiler statically removes ARC when it can prove it doesn’t need it (or when you annotate it because where you’re getting it from is manually managing and giving you ownership of the reference). So within a function or cross function with LTO (although it looks like swift doesn’t yet have LTO [1] so I’m not sure about cross-module optimizations). > When receiving a return result from such a function or method, ARC releases the value at the end of the full-expression it is contained within, subject to the usual optimizations for local values. Quote from [2] (section 6 has the full details about optimizations). I believe [3] might be the compiler pass. There actually is some elision that happens at runtime if you install an autoreleasepool if I recall correctly. I did actually work at Apple so that’s where my recollection comes from although it’s been 8 years since then and I didn’t work on the compiler side of things so my memory could be faulty. [1] https://github.com/apple/swift/pull/32233 https://github.com/apple/swift/pull/32233 [2] https://opensource.apple.com/source/lldb/lldb-112/llvm/tools/clang/docs/AutomaticReferenceCounting.html https://opensource.apple.com/source/lldb/lldb-112/llvm/tools... [3] https://llvm.org/doxygen/group__ARCOpt.html https://llvm.org/doxygen/group__ARCOpt.html
- pjmlp 4y agoSwift and Objective-C ARC performance is quite poor.
- KerrAvon 4y agoCompared to what, though? And is that still the case if all OS components use whatever it is, as opposed to a few applications? Memory efficiency is crucial for overall system performance, and ARC is highly memory-efficient compared to every production GC I’m aware of.
- pjmlp 4y agohttps://github.com/ixy-languages/ixy-languages https://github.com/ixy-languages/ixy-languages
- astrange 4y agoPeak memory is not the only reason ARC is memory-efficient though, the main reason is that it has better memory reading behavior because it doesn't have to scan for pointers. Server GCs assume all memory containing pointers is cheap to access, which is not true if some of it is swapped out.
- vlovich123 4y agoiOS ships the same speed phones as Android with half the RAM. So I’d say here’s a real comparison of ARC vs tracing GC.
- pjmlp 4y agoAnd the Android rules the mobile world with 80% market share. Also iOS applications tend to crash due to memory leaks or not enough memory being available. So yeah a real comparison.
- kaba0 4y agoIphones are 3 generations ahead in terms of single core CPU performance, so that’s just a biased take.
- throwaway81523 4y agoThe conventional wisdom is that evacuating (copying) GC's win over malloc/free since 1) the GC touches only the live data and not the garbage, and 2) it compacts the active memory periodically, which improves its cache and (when relevant) paging hit rates. Obviously though, this will be situation dependent.
- kenniskrag 4y agoHow is that possible? Sounds counter-intuitive. Do you have a recommendation for reading?
- lispm 4y agoThere was an Ada implementation on the Lisp Machine, that might have been using GC.
- pjmlp 4y agoAs for .NET and JVM implementations, but that is a consequence of underlying platform, just like C++/CLI and C++/CX, and none of them have been that big into the Ada compiler market.
- syngrog66 4y ago> and further removed from it on ISO Ada 2012. and in that precise moment Ada proved it had garbage collection all along
- pjmlp 4y agoBy that measure same applies to C++, as C++20 removed the GC API introduced in C++11.
- polynomial 4y agoAh, same as C++ it sounds like.
- mcculley 4y agoWhich means no library can depend on it, pushing memory management responsibilities into calling code.