Live data from Hacker News

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

akitasoftware.com

141–150 of 231 posts

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

#141
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…

> They stopped compiling regexps on the fly and moved the regexps to package variables. (I actually don't know if this was a significant win; there might just be the three big wins.)

Anecdotally, this could be a huge win, depending on how often it's called.

A guy I was working with, new to Go, was writing a router config parser and asked why it was so slow.

The first thing I did was moved regexp.Compile from a hot path into a broader scope. It went from something like 40 seconds down to 2 on my machine.

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

#142

Earlier quoted context omitted.

I feel that this is one of those common misconceptions about Rust. Rust's memory management is nothing like C or non-modern C++'s with malloc/free or new/delete. Rust uses modern-C++'s RAII model, typically, to allocate memory. The compiler is smart enough to know when to call drop() (which is essentially free/delete, but with the possibility of additional behavior). You can also call drop() yourself. What I think pe…

Tangentially, I did a bit of Rust work recently. I was sadly unable to find a concise credible answer to a rather elementary best-practices question: How does ownership interact with nested datastructures? Is it possible to build a heap tree without Boxing every node explicitly?

You might be interested in this:

https://rust-unofficial.github.io/too-many-lists/

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

#143
post #107
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…

It's a question I ask often in interview, how do you upload a 5GB file over the network with only 1MB of memory.

Well I left Kentucky back in '49 and went to Detroit work'n on assembly line..

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

#144

Earlier quoted context omitted.

Right, but GC encourages you to not think about memory at all until the program starts tipping over and fixing the underlying cause of the leak now requires an architecture change because the "we hold onto everything" assumption got baked into the structure in 2 places that you know about and 5 that you don't. I don't miss the rote parts of manual memory management, but it had the enormously beneficial side effect of…

> Right, but GC encourages you to not think about memory at all I’ve come to a new obvious realisation with this sort of thing recently: if you care about some metric, make a test for it early and run it often. If you care about correctness, grow unit tests and run them at least every commit. If you care about performance, write a benchmark and run it often. You’ll start noticing what makes performance improve and re…

Not so much. Here we have an example of a memory pressure problem that's evident only under high load in realistic environments. This is a classic problem with performance engineering: it's usually difficult to do realistic automated load testing. Instead, you end up running lab experiments, which are time-consuming to set up.

The whole post is essentially about how tricky it was to surface the problems their customers were seeing in the field. I'd resist the urge to respond to that with a platitude about automated testing.

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

#145
post #27

Earlier quoted context omitted.

I feel that this is one of those common misconceptions about Rust. Rust's memory management is nothing like C or non-modern C++'s with malloc/free or new/delete. Rust uses modern-C++'s RAII model, typically, to allocate memory. The compiler is smart enough to know when to call drop() (which is essentially free/delete, but with the possibility of additional behavior). You can also call drop() yourself. What I think pe…

> Additionally, Rust is pretty in-your-face when it comes to concurrency and sharing memory across thread/task boundaries. Use channels whenever possible.

Channels are not always the best solution (unless you're referring to Rust channels?)

https://www.jtolio.com/2016/03/go-channels-are-bad-and-you-s...

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

#146
post #120
post #101

Earlier quoted context omitted.

And Go too! It's always fun to see posts from around 2014/2015 complaining about how every submission to Hacker News is now "I wrote X in Go", while now Go is the boring stuff and Rust is the hot new thing. I wonder what will be the next Rust though.

Some GC based language with dependent types.

Nim is on the way up in HN posts...

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

#147
post #138

Earlier quoted context omitted.

> The author could have just kept "Taming Go's Memory Usage". It’s their article. They can choose to write it however they want. You may find this type of humor distasteful, fine, write your articles that way. As a user of both rust and golang, I chuckled at the headline and then forgot about it.

a

TFA doesn’t argue that one is better than the other? Maybe you’re commenting on unrelated “click bait shit”?

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

#148
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…

> They were using a protobuf diffing library that used `reflect` under the hood, which allocates. They generated their own explicit object inspection thingies.

IIRC it is `reflect.Type.FieldXXX` which is the main culprit of allocations. Since the number of types in a typical application are bounded and small, you can get pretty far by just precomputing/caching struct fields.

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

#149

Earlier quoted context omitted.

Tangentially, I did a bit of Rust work recently. I was sadly unable to find a concise credible answer to a rather elementary best-practices question: How does ownership interact with nested datastructures? Is it possible to build a heap tree without Boxing every node explicitly?

You might be interested in this: https://rust-unofficial.github.io/too-many-lists/

Thanks. Saw that before, but the credibility/length ratio wasn't high enough to read it more carefully. It appears that we do have to Box/Rc/Arc nodes in a recursive datastructure. Doable, but a bit on the inconvenient side.

    struct Node {
        elem: i32,
        next: Option>,
    }

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

#150

Earlier quoted context omitted.

> Right, but GC encourages you to not think about memory at all I’ve come to a new obvious realisation with this sort of thing recently: if you care about some metric, make a test for it early and run it often. If you care about correctness, grow unit tests and run them at least every commit. If you care about performance, write a benchmark and run it often. You’ll start noticing what makes performance improve and re…

Not so much. Here we have an example of a memory pressure problem that's evident only under high load in realistic environments. This is a classic problem with performance engineering: it's usually difficult to do realistic automated load testing. Instead, you end up running lab experiments, which are time-consuming to set up. The whole post is essentially about how tricky it was to surface the problems their custome…

Yes it can be difficult to do realistic automated load testing. But I suppose I see this as more evidence that if you're going to do load testing, do it right! In complex systems you often need real world usage data, or your metrics won't predict reality.

I've been running into this a lot writing software for collaborative editing. Randomly generated editing traces work fine for correctness testing. But doing performance testing with random traces is unrepresentative. The way people move their cursors around a text box while editing is idiosyncratic. Lots of optimizations make performance worse with random editing histories, but improve performance for real world data sets.

Post reply on HN