Live data from Hacker News

Taming Go’s memory usage, or how we avoided rewriting our client in Rust

akitasoftware.com

91–100 of 231 posts

Re: Taming Go’s memory usage, or how we avoided rewriting our client in Rust

#91
post #39

The big wins in this article, in what I believe was the order of impact: * They do raw packet reassembly using gopacket, and gopacket keeps TCP reassembly buffers that can grow without bound when you miss a TCP segment. They capped the buffers, and the huge 5G spikes went away. * They were reading whole buffers into memory before handing them off to YAML and JSON parsers. They passed readers instead. * They were usin…

Yeah, and perhaps someone who knows rust well could argue some things are easier to do right in rust. For example, in the second bullet, pass readers could be more of the norm in libraries since rust in a systems programming language. Third bullet to similar point.

I'm not saying rust is better or they made the wrong choice, sounds like C++ would let users easily make the same "wrong" choices, just interesting to carry the thoughts through a bit further.

Re: Taming Go’s memory usage, or how we avoided rewriting our client in Rust

#92
post #80

Earlier quoted context omitted.

"developer velocity" is also, in some sense, a semantic question. I am special, of course, but basically, if you include things like "time fixing bugs that would have been prevented in Rust in the first place", my velocity is higher in Rust than in many GC'd languages I've used in the past. It just depends on so many factors it's impossible to say definitively one way or another.

I have trouble believing this, at least in any generalizable way. I'm comfortable in both Go and Rust at this point (my Rust has gotten better since last year when I was griping about it on HN), and it's simply the case that I have to think more carefully about things in Rust because Go takes care of them for me. It's not a "think more carefully and you're rewarded with a program that runs more reliably and so you ma…

This jives very well with my experience. I like writing Rust, but I do so well aware that I could write the same thing in Go and still have quite a lot of time left-over for debugging issues.

I can also get user feedback sooner and thus pivot my implementation more quickly, which is a more subtle angle that is so rarely broached in these kinds of conversations.

The places where I think the gap between Go and Rust is the smallest (due to Rust's type system) are things like compilers where you have a lot of algebraic data types to model--Rust's enums + pattern matching are great here.

Re: Taming Go’s memory usage, or how we avoided rewriting our client in Rust

#94
post #78

Earlier quoted context omitted.

But thinking about lifetimes and RAII is 90% of memory management. Basically whether you write C, C++, or Rust, you have to track ownership the same ways, the only thing that changes is how much the compiler helps you with that. However, if you write your program in Java, Lisp or Haskell, you simply do not care about ownership for memory-only objects, and can structure your program significantly differently. This can…

With modern C++ your memory checklist is two steps: put it on the stack, put it in a unique_ptr on the stack. There are more steps after that, but you almost never get to them and wouldn't remember them if you discovered the need for them (which is okay because you never get there).

Your checklist is only covering the simplest case, direct ownership of small data structures.

I'm not going to put a large array on the stack. I'm not going to pass unique_ptr (exclusive ownership) of every resource I allocate to every caller. I still need to decide between passing a copy, a unique_ptr, a reference, or a shared_ptr. When I design a data structure with interior pointers, I need to define some ownership semantics and make sure they are natural (for example, in a graph that supports cycles, there is no natural notion of ownership between graph nodes).

These are all questions that are irrelevant in a GC langauge, for memory resources.

Re: Taming Go’s memory usage, or how we avoided rewriting our client in Rust

#95
post #2

Bit confused by this part of the article: > PRO-REWRITE: Rust has manual memory management, so we would avoid the problem of having to wrestle with a garbage collector because we would just deallocate unused memory ourselves, or more carefully be able to engineer the response to increased load. > ANTI-REWRITE: Rust has manual memory management, which means that whenever we’re writing code we’ll have to take the time…

I also was confused about that part but for another reason: The whole post is basically "despite go having a GC we had to manually manage the memory to make it work" and then the anti-rewrite is "go does memory management for us". IMO people sometimes have really weird ideas what is and isn't part of managing memory.

Re: Taming Go’s memory usage, or how we avoided rewriting our client in Rust

#96
post #2

Bit confused by this part of the article: > PRO-REWRITE: Rust has manual memory management, so we would avoid the problem of having to wrestle with a garbage collector because we would just deallocate unused memory ourselves, or more carefully be able to engineer the response to increased load. > ANTI-REWRITE: Rust has manual memory management, which means that whenever we’re writing code we’ll have to take the time…

Yes, Rust kinda doesn't fit super cleanly into a very black/white binary here. It is automatic in the sense that you do not generally call malloc/free. The compiler handles this for you. At the same time, you have a lot more control than you do in a language with a GC, and so to some people, it feels more manual. It's also like, a perception thing in some sense. Imagine someone writes some code. They get a compiler e…

It's very much a confusing process. If C-styled memory management is skydiving and Python is parachuting, Rust can feel a bit like bungee-jumping. It's neither working for or against you, but it will behave in a specific way that you have to learn to work around. Your reward for getting better at that system is less mental hassle overall, but it's definitely a strange feeling, particularly if you're already comfortable with traditional memory management.

Re: Taming Go’s memory usage, or how we avoided rewriting our client in Rust

#97
post #39

The big wins in this article, in what I believe was the order of impact: * They do raw packet reassembly using gopacket, and gopacket keeps TCP reassembly buffers that can grow without bound when you miss a TCP segment. They capped the buffers, and the huge 5G spikes went away. * They were reading whole buffers into memory before handing them off to YAML and JSON parsers. They passed readers instead. * They were usin…

Yeah, and perhaps someone who knows rust well could argue some things are easier to do right in rust. For example, in the second bullet, pass readers could be more of the norm in libraries since rust in a systems programming language. Third bullet to similar point. I'm not saying rust is better or they made the wrong choice, sounds like C++ would let users easily make the same "wrong" choices, just interesting to car…

io.Reader() and io.Writer() are used everywhere in Go, it's really a standard practice.

https://tour.golang.org/methods/21

Re: Taming Go’s memory usage, or how we avoided rewriting our client in Rust

#98
post #80

Earlier quoted context omitted.

I have trouble believing this, at least in any generalizable way. I'm comfortable in both Go and Rust at this point (my Rust has gotten better since last year when I was griping about it on HN), and it's simply the case that I have to think more carefully about things in Rust because Go takes care of them for me. It's not a "think more carefully and you're rewarded with a program that runs more reliably and so you ma…

This jives very well with my experience. I like writing Rust, but I do so well aware that I could write the same thing in Go and still have quite a lot of time left-over for debugging issues. I can also get user feedback sooner and thus pivot my implementation more quickly, which is a more subtle angle that is so rarely broached in these kinds of conversations. The places where I think the gap between Go and Rust is…

I always miss match and options (I could go either way on results, which tend to devolve into a shouting match between my modules with the type system badly refereeing). But my general experience is, I switch from writing in Rust to Go, and I immediately notice how much more quickly I'm getting code into the editor. It's pretty hard to miss the difference.

Re: Taming Go’s memory usage, or how we avoided rewriting our client in Rust

#99
post #2

Bit confused by this part of the article: > PRO-REWRITE: Rust has manual memory management, so we would avoid the problem of having to wrestle with a garbage collector because we would just deallocate unused memory ourselves, or more carefully be able to engineer the response to increased load. > ANTI-REWRITE: Rust has manual memory management, which means that whenever we’re writing code we’ll have to take the time…

While you may not have to directly call malloc and free in Rust, the memory management still feels very manual compared to a language with GC. When I want to pass an object around I have to decide whether to pass a &_, a Box, Rc, or Rc>, or a &Rc>, etc. And then there are lifetime parameters, and having to constantly be aware of relative lifetimes of objects. Those are all manual decisions related to memory management that you have to constantly make in Rust that you wouldn't need to think about in Go or Python or Java.

Similarly, idiomatic modern C++ rarely needs new and delete calls, but I'd still say it has manual memory management.

I suppose it's reasonable to talk about degrees of manual-ness, and say that memory management in Rust or modern C++ is less manual than C, but more manual than Go/Python/Java.

Re: Taming Go’s memory usage, or how we avoided rewriting our client in Rust

#100

"How we avoided rewriting in Rust" feels like clickbait given that the answer is "our problems were algorithmic, not language-specific"

Memory issues are amplified a bit by garbage collection though, in that every pointer must be stored twice, and collection will take time and evict things from cpu cache etc. If you were struggling with this, turning to Rust might be a thing people would try, even if it wasn't fixing the first order problems, and only addressing the 2nd order ones.

The whole post is about how Rust turned out not to be the answer to exactly this problem.
Post reply on HN