3 ms·
the CPU utilisation ... was around 370-380%! I was now totally stumped I guess that his code allocates a huge number of objects as all input and output classes
by silvestrov 13y ago
the CPU utilisation ... was around 370-380%! I was now totally stumped
I guess that his code allocates a huge number of objects as all input and output classes are final. The JVM's garbage collector is able to run concurrently, so I guess it's the GC that takes so much CPU. AFAIK Go uses mark-and-sweep collection which is very slow.
That would explain the unexpected difference in running time as the JVM's garbage collector is very mature and fast.
- NateDad 13y agoWhen Go is slow, it's almost always due to excess garbage creation. This can usually be fixed by optimizing your memory usage... but I'm guessing an experienced java professional may not think of that precisely because java's garbage collection is so damn good most of the time.
- yelnatz 13y agoI know theres a []byte mempool project on github.[1] Still pretty early though, I don't think it can do dynamic sizes? [1] https://github.com/thejerf/gomempool https://github.com/thejerf/gomempool
- NateDad 13y agoMost of the time it's really just a matter of reusing data structures rather than creating new ones and throwing them away immediately, over and over again.
- yelnatz 13y agoYep, I think that's basically the idea there. "You already have this []byte, don't throw it away, give it back to the pool so you can reuse it."
- jerf 13y agoPooling dynamic sizes is a bit tricky; if a user requests 1000 bytes and you hand them 1000 bytes, you're in some trouble if the next guy asks for 1002. I round all allocations to powers-of-two in there. It does dynamic size but at the moment I don't have separate per-bucket pooling settings; it's the obvious next feature. The stats collection is intended to show me whether that's a useful feature. In testing so far it hasn't been in my specific use case, but I'm still only hitting my application with load testing, not real load. The use case for gomempool is relatively transient buffers, where that is a win vs. generating a lot of []bytes. Rounding to power-of-2 is a traditional, theoretically solid answer. There's also as somewhat more unusual one using Fibonacci numbers, which Erlang uses to size its memory hunks. Fortunately the interface is agnostic, if that's advantageous someday user code doesn't need to notice the difference. I couldn't resist the first time in my career in which I could justify some bit bashing: https://github.com/thejerf/gomempool/blob/master/pool.go#L395 https://github.com/thejerf/gomempool/blob/master/pool.go#L39... :)
- SigmundA 13y agoYep all that extra CPU utilization on the the other cores is just garbage cleanup. Go has a stop the world collector, hence the poor performance and single core usage. Both versions would benefits greatly from reusing instances instead of generating huge amounts of garbage, however the Go version would benefit the most. With the Java version he is simply throwing hardware at the garbage. Know thy garbage collector!