This is exactly as I'd expect - about 40MB of memory being used. The sudden drop-offs are the GC doing its job - I verified this by playing with GOGC.
This will be a long-running service, so I need to understand the discrepancy between expected and actual system memory usage. I'm clearly missing something. Any insight?
--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/xsgkSALra-g/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
I was able to provoke my service into *really* misbehaving in a weird way. As I mentioned, this is an SSH proxy. I've been very careful to defer close everything, and I've verified these goroutines *are* closing with top-level defers that outputs to the log.When I start the service, I'm listening for connections. There's no leak at this point. The service rests at around 15MB.When I receive a connection, I kick off a goroutine to handle it, and in that goroutine, I kick off 3 more - one for proxying each stdout, stderr, and stdin. Again - all of these *do* close when I expect them to. After receiving just one SSH connection, dialing to another server, and successfully proxying between them, leaks start happening like crazy, even when no new connections come in. Here's the thing, though... The leaks are only obvious if I use a big []byte buffer when reading and writing between the different connections' channels. The leak is about 5MB/second when I use any sized buffer greater than 1MB. This seems to be the upper bound - if I use even bigger buffers, this doesn't leak any worse.So... looking at my active goroutines before and after this first SSH connection proxy, I *do* see something interesting, but I haven't the time tonight to dive into the call stacks. These two goroutines weren't there before my first SSH proxy, but they stick around after:I'm a little confused why I'm seeing net/http here. I *do* make an Http request for authorization of the public key during the SSH handshake, but I'm pretty sure that's not the issue. I'm also using pprof and hosting the server on 6060 as I mentioned above. Those should be the only explicit uses of http on my end.Any ideas? I know it's tough without sharing my code :(
I was able to provoke my service into *really* misbehaving in a weird way. As I mentioned, this is an SSH proxy. I've been very careful to defer close everything, and I've verified these goroutines *are* closing with top-level defers that outputs to the log.When I start the service, I'm listening for connections. There's no leak at this point. The service rests at around 15MB.When I receive a connection, I kick off a goroutine to handle it, and in that goroutine, I kick off 3 more - one for proxying each stdout, stderr, and stdin. Again - all of these *do* close when I expect them to. After receiving just one SSH connection, dialing to another server, and successfully proxying between them, leaks start happening like crazy, even when no new connections come in. Here's the thing, though... The leaks are only obvious if I use a big []byte buffer when reading and writing between the different connections' channels. The leak is about 5MB/second when I use any sized buffer greater than 1MB. This seems to be the upper bound - if I use even bigger buffers, this doesn't leak any worse.
This now smells like a tight loop somewhere. I just did a 30 second profile, and got this - is this a concern?
Total: 442 samples
442 100.0% 100.0% 442 100.0% runtime.mach_semaphore_timedwait
0 0.0% 100.0% 442 100.0% notetsleep
0 0.0% 100.0% 442 100.0% runtime.MHeap_Scavenger
0 0.0% 100.0% 442 100.0% runtime.gosched0
0 0.0% 100.0% 442 100.0% runtime.notetsleepg
It's reassuring that I can chart this madness... but, at 75MB, it still only accounts for about 25% of what the system is reporting, at around 320MB. The OS says I have 8 threads, fwiw.
I still think the two goroutines I included in my previous message are fishy.
Okay, now that I've been able to exaggerate this "leak", it's showing up in the pprof charts. So, I'm now seeing two weird things. The first is clearly this unidentified memory usage, and why it's exaggerated when I use bigger buffers to copy between I/O streams. The second is the 4X++ discrepancy between the runtime's stats and the OS. Dave suggested that it might be OS threads - I checked: OSX said the process was using 8 threads.
Here's a recent graph, showing that the runtime *is* aware of the memory usage. It's a ton of little bits that are getting GC'd.This now smells like a tight loop somewhere. I just did a 30 second profile, and got this - is this a concern?
Total: 442 samples
442 100.0% 100.0% 442 100.0% runtime.mach_semaphore_timedwait
0 0.0% 100.0% 442 100.0% notetsleep
0 0.0% 100.0% 442 100.0% runtime.MHeap_Scavenger
0 0.0% 100.0% 442 100.0% runtime.gosched0
0 0.0% 100.0% 442 100.0% runtime.notetsleepg
It's reassuring that I can chart this madness... but, at 75MB, it still only accounts for about 25% of what the system is reporting, at around 320MB. The OS says I have 8 threads, fwiw.
I still think the two goroutines I included in my previous message are fishy.
On Wednesday, August 27, 2014 12:55:21 AM UTC-4, Jesse McNelis wrote:On Wed, Aug 27, 2014 at 2:29 PM, Blake Caldwell <bl...@fogcreek.com> wrote:
I was able to provoke my service into *really* misbehaving in a weird way. As I mentioned, this is an SSH proxy. I've been very careful to defer close everything, and I've verified these goroutines *are* closing with top-level defers that outputs to the log.When I start the service, I'm listening for connections. There's no leak at this point. The service rests at around 15MB.When I receive a connection, I kick off a goroutine to handle it, and in that goroutine, I kick off 3 more - one for proxying each stdout, stderr, and stdin. Again - all of these *do* close when I expect them to. After receiving just one SSH connection, dialing to another server, and successfully proxying between them, leaks start happening like crazy, even when no new connections come in. Here's the thing, though... The leaks are only obvious if I use a big []byte buffer when reading and writing between the different connections' channels. The leak is about 5MB/second when I use any sized buffer greater than 1MB. This seems to be the upper bound - if I use even bigger buffers, this doesn't leak any worse.When you say 'leak' what are you referring to?Are you saying that the memory that the runtime reports it's using is that much less than what the OS says the process is using? aand that the difference grows over time?
Okay, now that I've been able to exaggerate this "leak", it's showing up in the pprof charts. So, I'm now seeing two weird things. The first is clearly this unidentified memory usage, and why it's exaggerated when I use bigger buffers to copy between I/O streams. The second is the 4X++ discrepancy between the runtime's stats and the OS. Dave suggested that it might be OS threads - I checked: OSX said the process was using 8 threads.
Here's a recent graph, showing that the runtime *is* aware of the memory usage. It's a ton of little bits that are getting GC'd.This now smells like a tight loop somewhere. I just did a 30 second profile, and got this - is this a concern?
Total: 442 samples
442 100.0% 100.0% 442 100.0% runtime.mach_semaphore_timedwait
0 0.0% 100.0% 442 100.0% notetsleep
0 0.0% 100.0% 442 100.0% runtime.MHeap_Scavenger
0 0.0% 100.0% 442 100.0% runtime.gosched0
0 0.0% 100.0% 442 100.0% runtime.notetsleepgIt's reassuring that I can chart this madness... but, at 75MB, it still only accounts for about 25% of what the system is reporting, at around 320MB. The OS says I have 8 threads, fwiw.
I still think the two goroutines I included in my previous message are fishy.
On Wednesday, August 27, 2014 12:55:21 AM UTC-4, Jesse McNelis wrote:On Wed, Aug 27, 2014 at 2:29 PM, Blake Caldwell <bl...@fogcreek.com> wrote:
I was able to provoke my service into *really* misbehaving in a weird way. As I mentioned, this is an SSH proxy. I've been very careful to defer close everything, and I've verified these goroutines *are* closing with top-level defers that outputs to the log.When I start the service, I'm listening for connections. There's no leak at this point. The service rests at around 15MB.When I receive a connection, I kick off a goroutine to handle it, and in that goroutine, I kick off 3 more - one for proxying each stdout, stderr, and stdin. Again - all of these *do* close when I expect them to. After receiving just one SSH connection, dialing to another server, and successfully proxying between them, leaks start happening like crazy, even when no new connections come in. Here's the thing, though... The leaks are only obvious if I use a big []byte buffer when reading and writing between the different connections' channels. The leak is about 5MB/second when I use any sized buffer greater than 1MB. This seems to be the upper bound - if I use even bigger buffers, this doesn't leak any worse.When you say 'leak' what are you referring to?Are you saying that the memory that the runtime reports it's using is that much less than what the OS says the process is using? aand that the difference grows over time?
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
It's only once I start pushing the upper limit higher that I see more of a swing in memory usage, but that's expected - GC isn't jumping in until that upper limit is reached.
The confusing part is what OSX is telling me, and you might be right that it's just dumb, or that it involves threads. When I start the app, the system reports the service using 6 threads. As I start doing more, it goes to 8. I'll start running this primarily on Linux and see what it says.
Thanks guys - I'll post again when I see what it's doing in Linux.
--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/xsgkSALra-g/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
(heh, shrugs)
I haven't used "go list" before... I assume I append my package at the end of that command. Most of those are imported via go.crypto/ssh:
I'm having a hard time understanding why my service is using up 400MB-1GB of system memory, as reported by top on Linux, and Activity Monitor on OS X. I figured I'm leaking goroutines or my 32kb buffers, so I tried:- reusing memory buffers (no change)- monitoring goroutines and heap with net/http/pprof listening on 6060 - no leaked goroutines and memory was as expected, (matching my graphs below)- exiting with panic to view the lingering goroutines - none- runtime.MemStats graphing (see below)I used the info from this post to graph my memory usage, and found no misbehavior:Here's a the service after a short time:And here it is after running all night:This is exactly as I'd expect - about 40MB of memory being used. The sudden drop-offs are the GC doing its job - I verified this by playing with GOGC.
However... When I use top (Linux and OSX) or Activity Monitor (OSX), the service quickly ramps up to 200MB, then slowly raised to over a GB when running over night. It looks like it then dropped down to 400MB, and started climbing again.This will be a long-running service, so I need to understand the discrepancy between expected and actual system memory usage. I'm clearly missing something. Any insight?
--