-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
runtime: let idle OS threads exit #14592
Comments
Cleaning up the idles would benefit mobile (android) deployments since threads are very precious resource there. Perhaps a settings to toggle cleanup idle threads or not is appropriate for those that would trade absolute performance for reduced resource usage. |
I don't think this has anything to do with GC. It sounds like a general runtime issue instead. Assigning to @aclements to triage for Go 1.8. |
Cleaning up new threads right after they've been used seemed potentially wasteful, so obviously some form of periodic cleanup felt more realistic. GC is a timeframe the runtime is already setting aside for periodic cleanup, so that's what I went with initially. But I agree that it doesn't necessarily need to be tied to the GC for any particular reason. |
I know there's plenty of other work on everyone's respective plates but has anyone had a chance to think about this some more? |
As i know, GC will return allocated heap memory to system after 5 minutes idle, can it also exit idle threads? |
This is certainly technically possible, but the devil's in the details. For example, we often manipulate pointers to Ms (the structure representing an OS thread) in contexts that don't interact with stop-the-world and can't have write barriers, which means it's difficult to know when we're actually done with an M and can safely recycle it. Even if we don't release the M structure itself and just release the OS thread, we have to know when we can safely reuse the M for another OS thread to avoid races. |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Punting to Go 1.10. |
CL https://golang.org/cl/46037 mentions this issue. |
Currently, threads created by the runtime exist until the whole program exits. For #14592 and #20395, we want to be able to exit and clean up threads created by the runtime. This commit implements that mechanism. The main difficulty is how to clean up the g0 stack. In cgo mode and on Solaris and Windows where the OS manages thread stacks, we simply arrange to return from mstart and let the system clean up the thread. If the runtime allocated the g0 stack, then we use a new exitThread syscall wrapper that arranges to clear a flag in the M once the stack can safely be reaped and call the thread termination syscall. exitThread is based on the existing exit1 wrapper, which was always meant to terminate the calling thread. However, exit1 has never been used since it was introduced 9 years ago, so it was broken on several platforms. exitThread also has the additional complication of having to flag that the stack is unused, which requires some tricks on platforms that use the stack for syscalls. This still leaves the problem of how to reap the unused g0 stacks. For this, we move the M from allm to a new freem list as part of the M exiting. Later, allocm scans the freem list, finds Ms that are marked as done with their stack, removes these from the list and frees their g0 stacks. This also allows these Ms to be garbage collected. This CL does not yet use any of this functionality. Follow-up CLs will. Likewise, there are no new tests in this CL because we'll need follow-up functionality to test it. Change-Id: Ic851ee74227b6d39c6fc1219fc71b45d3004bc63 Reviewed-on: https://go-review.googlesource.com/46037 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
Issue #22439 has an example of a problem caused by not exiting idle Ms (and freeing their stack memory). |
Oh, geez. Good call. Could this be a problem even for the current thread exiting we do? Something like:
Is there any way to query whether there are pending I/O operations on a thread? I'm wondering if we could just block a thread from exiting until all of its pending I/Os are done. |
I did not know that OS threads are exiting at this moment. Is there a way to verify your scenario above? What would be the program to do that? I can do 1. by reading from a TCP connection, but how would do I force 2. and 3?
I do not know of any. You could call GetCurrentThreadId Windows API to get current thread id, but you, probably, can already work that information out of whatever you have recorded for Gs and Ms. Surely we could mark Ms when IO starts, and remove that mark once IO completes. Alex |
Change https://golang.org/cl/85662 mentions this issue: |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
@superajun-wsj Please add text as text, not as an image. Actual text is much easier to read than text in an image. Thanks. |
Hi @superajun-wsj Not sure that it is good solution. When the child process is created by one thread called A with |
Any news regarding this? In my particular case I am developing for IoT hardware running Linux that only has 1 vCPU and 128 MB of memory. From my testing I am estimating that a single thread in my case has a 80 KiB memory overhead (which is strange in itself since a Ubuntu 20.04 LTS amd64 server I also tested on approx. has an overhead of only 8 KiB). My program after running for a week uses on average 40 goroutines at any given time, however the thread count after a week is 220+. This would mean the remaining threads (if each goroutine is scheduled on it's own thread) memory overhead is over 14 MiB ( I would be perfectly happy if there was a function that we could call in the runtime package to trigger a GC-like thread cleanup. |
if you go process did not create thread itself(like by set block to socket), you could use debug.SetMaxThreads to limit max number of threads go create |
added thread count to runtime stats. go never closes OS threads once opened, see: golang/go#14592
Any update on this? |
There is no update. |
1 similar comment
There is no update. |
go version
)?1.5.3, 1.6
go env
)?x86_64 - OSX and Linux
Any golang program will create a new OS thread when it needs to if things are blocked. But these threads aren't ever destroyed. For example, a program using 7 goroutines might have 40+ OS threads hanging around. The numbers will surely get much higher as traffic fluctuates against a golang server process throughout the day.
Once an OS thread has been idle long enough, I would have expected it to be destroyed. Being recreated if needed. Expanding and contracting like the relationship between the heap and GC.
The many OS threads that were created hang around even with an idle program and very few goroutines.
After doing some reading into other (closed) issues on this repo dating back to 2012 - including the one where
SetMaxThreads
was introduced - I'm curious, why keep the OS threads around instead of cleaning them up?The text was updated successfully, but these errors were encountered: