6 ms·
> It's because Go still has a garbage collector, and that always comes with a price tag. This is not really true, at least not as such a general claim. 1. mal
by rbehrends 10y ago
> It's because Go still has a garbage collector, and that always comes with a price tag.
This is not really true, at least not as such a general claim.
1. malloc()/free() can be either faster or slower than garbage collection. It depends on implementation details and is situational. Note in particular the issues of memory locality and temporary allocations.
2. This assumes an omniscient programmer who has perfect knowledge of when to allocate or free. In reality, memory management is a traditional cross-cutting concern, and in order to deal with it manually in a modular fashion, you will typically introduce additional overhead. Examples:
- in C++, m[a] = b, where m is a map, and a and b are strings requires that both a and b are being copied. This is not necessary in a GCed language.
- naive reference counting has significant overhead, significantly more than a modern tracing GC.
- even unique_ptr has overhead (though less so than reference counting).
Garbage collection allows you to have the necessary global knowledge to (mostly) eliminate memory management as a cross-cutting concern, because the GC is allowed to peek behind the scenes and ignore abstraction boundaries.
3. Things that C is fast at is usually also allocation-free code, i.e. iterating over arrays or matrices. The performance of such code is not going to be any different in a GCed language, assuming an optimizer of comparable caliber.
- swift 10y agoI agree with almost everything in your post, but I'm surprised about your comment that unique_ptr has overhead. Since unique_ptr is a single item struct with no vtable I'd expect no space overhead at all. Similarly, while it does need to run code in its destructor, I'd expect a trivial, non-virtual destructor like that to be reliably inlined and the result to be no worse than a manual call to delete. If that's not true, though, I'd definitely like to know, so please let me know if I've missed something.
- rbehrends 10y agoIt has runtime overhead whenever a move assignment occurs. You have to check if the target of the assignment is null (or otherwise call the destructor) and you have to assign null to the source. This is all overhead compared to a plain pointer assignment. An optimizing compiler will of course try to eliminate most of that overhead, but that's not always possible.
- lossolo 10y ago>> - in C++, m[a] = b, where m is a map, and a and b are strings requires that both a and b are being copied. This is not necessary in a GCed language. You don't need to make copy. std::map<std::string, std::string> m; m.emplace(std::make_pair(std::string("a"), std::string("a")));
- rbehrends 10y ago1. You are assuming here that a and b will not be used anymore and are optimizing for a special case. 2. The general problem that I was trying to illustrate is that shared ownership requires either reference counting or avoiding it through copying if you don't have automatic memory management.
- lossolo 10y agoYour example didn't had any assumptions. What you are assuming then? If you need to reuse variable in Go then it will also copy it inside the map so your point is even more invalid in that case.
- rbehrends 10y agoNo. In a GCed language, both the map and the original code can safely share a reference without having to worry about coordinating lifetime.
- lossolo 10y ago> In a GCed language, both the map and the original code can safely share a reference without having to worry about coordinating lifetime. Go is GCed language. Show me the code that will do what you claim (map[var1] = var2 and use var1(type string) and var2(type string) in later code) in Go.
- rbehrends 10y agoI'll give you OCaml: let addr s = 2 * (Obj.magic s) + 1 let main () = let table = Hashtbl.create 0 in let key = "foo" and value = "bar" in Hashtbl.add table key value; Hashtbl.iter (fun key' value' -> Printf.printf "%b %b %x %x %x %x\n" (key == key') (value == value') (addr key) (addr key') (addr value) (addr value') ) table let () = main () This prints: true true 10cbd2490 10cbd2490 10cbd2378 10cbd2378 The exact addresses may vary from run to run. Note that == is reference equality in OCaml. I'm honestly baffled why you think that there is a need to copy the variables or why you can't use them later or whatever you believe there.