3 ms·
This is a straw man. Yes, of course, given the same code and allocation pattern, there are many cases where tracing GC will give you higher throughput than ref
by gok 8y ago
This is a straw man.
Yes, of course, given the same code and allocation pattern, there are many cases where tracing GC will give you higher throughput than reference counting, particularly once you add in cycle detection. But in GC'd languages and non-GC'd languages you write code with completely different allocation patterns. In non-GC'd environments you only need to refcount the small set of allocations that are actually shared. GC'd languages usually have semantics that require tracing for every allocation.
- weberc2 8y agoI don't see a straw man in the GP comment. He was clearly comparing tracing GC vs refcounting, while you're conflating memory management with value semantics. Specifically, you're assigning the benefits of value semantics to the absence of a GC and vice versa. While GC'd languages more frequently omit value semantics, they're orthogonal and there are languages (e.g., Go) that profit from both a GC and value semantics.
- titzer 8y ago> GC'd languages and non-GC'd languages you write code with completely different allocation patterns. [citation needed]
- pjmlp 8y agoPlenty of GC languages have value types and support for manual memory management. Mesa/Cedar, Active Oberon, Modula-3, D, System C#, Go, C#
- gok 8y agoSure, even Java lets you manually allocate memory via JNI, but negligible amounts of code written in those languages actually uses manual management. Reference counting is uncompetitive in those languages because idiomatic Java/C#/Go make lots of allocations and pass around lots of pointers with no lifetime semantics.
- Jweb_Guru 8y agoIt's worth noting that Go's value types are not actually memory safe, however, since it allows nontrivial concurrent mutations to shared multiword objects (as described in https://blog.stalkr.net/2015/04/golang-data-races-to-break-memory-safety.html https://blog.stalkr.net/2015/04/golang-data-races-to-break-m...). Unless that got fixed recently somehow? I believe in most of the other languages you mention, value types are restricted in various ways to avoid that problem (for instance, mutations are only allowed to value types on the stack that don't escape, or multiword value types can only be updated in ways that preserve data structure validity even if updates "tear", or multiword value types are immutable).
- pjmlp 8y agoWith the exception of Go and C#, there are no limitation on value types. All those languages are GC enabled systems programming languages. Regarding Go the memory safety in multithreaded code is orthogonal to having support for value types or not.
- Tarean 8y agoIf the manually allocated memory may contain references to managed objects then it still needs to be traced by the gc. That or you start pinning managed objects or pull everything related into manual world. Both kinda suck.
- pjmlp 8y agoManually allocated memory in some of those languages is only allowed in the context of unsafe packages. In any case, the point is that you should only do that for the code paths that actually matter, after profiling the application and not everywhere. Be productive, make use of the GC, naturally taking into the consideration the algorithms + data structures being used. If that is still not enough to meet the application's SLAs, then manually allocation comes into play.
- Jweb_Guru 8y agoIt's not orthogonal at all. Nontrivial mutations to multi-word sized values are inherently racy operations that can lead to UB if you don't have restrictions on how value types can be used. D isn't memory safe; Active Oberon employs mandatory object locking on writes (which is a rather heavy runtime solution); Cedar values are either immutable, or always valid with respect to word sized mutations (as far as I can tell, unions, for example, can only exist behind a pointer indirection). Modula 3 objects are not, as far as I can tell, value types (i.e. they must be heap-allocated and mutation creates a new record), and those are the only types it has where a "tearing" mutation could invalidate the runtime representation. So, I disagree: all of the languages you mentioned either are memory unsafe when you use multiword value types concurrently, have one of the restrictions I mentioned, or (in the case of Active Oberon) conservatively lock on all writes. These value types are not "unrestricted" compared to primitives, all of which can be mutated in-place without allocating or locking, or to heap objects, which can be updated atomically even for interesting values at the cost of an allocation. Moreover, the issue is intimately tied to GC, or more accurately to the programmer not having to explicitly keep track of whether objects are uniquely owned or not (which is generally the function of a GC). As a result, if garbage collected objects can hold references to nontrivial value types, there is almost no way to avoid this problem.