This is going to create 5000 OS threads. The loop runs really quickly, and 
since CGO cannot use Go routines, you quickly allocate 5000 OS threads.

See https://github.com/golang/go/issues/14592

> On Mar 4, 2025, at 1:26 PM, David Bell <davidbellou...@gmail.com> wrote:
> 
> Hi everyone,
> 
> I'm relatively new to Go and even newer to CGO, so I’d really appreciate any 
> guidance on an issue I’ve been facing.
> 
> Problem Overview
> 
> I noticed that when using CGO, my application's memory usage keeps 
> increasing, and threads do not seem to be properly cleaned up. 
> The Go runtime (pprof) does not indicate any leaks, but when I monitor the 
> process using Activity Monitor, I see a growing number of threads and 
> increasing memory consumption.
> 
> Observations
> Memory usage keeps increasing over time when using CGO, even after forcing 
> garbage collection.
> Threads spawned for CGO calls appear to not be released, causing a large 
> number of lingering threads.
> The issue is not present when using pure Go time.Sleep() instead of the CGO 
> function.
> Reproducible Example
> 
> I created a minimal program that reproduces the issue. The following 
> CGO-based code keeps allocating memory and does not free threads properly:
> 
> package main
> 
> import (
>       "fmt"
>       "runtime"
>       "runtime/debug"
>       "sync"
>       "time"
> )
> 
> /*
> #include <unistd.h>
> void cgoSleep() {
>   sleep(1);
> }
> */
> import "C"
> 
> func main() {
>       start := time.Now()
> 
>       var wg sync.WaitGroup
>       for i := 0; i < 5000; i++ {
>               wg.Add(1)
>               go func() {
>                       defer wg.Done()
>                       C.cgoSleep()
>               }()
>       }
>       wg.Wait()
> 
>       end := time.Now()
> 
>       // Force GC and free OS memory
>       runtime.GC()
>       debug.FreeOSMemory()
>       time.Sleep(10 * time.Second)
> 
>       var m runtime.MemStats
>       runtime.ReadMemStats(&m)
> 
>       fmt.Printf("Alloc = %v MiB", m.Alloc/1024/1024)
>       fmt.Printf("\tTotalAlloc = %v MiB", m.TotalAlloc/1024/1024)
>       fmt.Printf("\tSys = %v MiB", m.Sys/1024/1024)
>       fmt.Printf("\tNumGC = %v\n", m.NumGC)
>       fmt.Printf("Total time: %v\n", end.Sub(start))
> 
>       select {}
> }
> 
> Expected Behavior
> The memory usage should not continue rising indefinitely.
> Threads should be properly cleaned up when they finish executing.
> The behavior should be similar to the following pure Go equivalent, which 
> does not exhibit the issue:
> 
> 
> Actual Results With CGO (cgoSleep()):
> Memory Usage: 296 MB
> Threads: 5,003
> System Memory (Sys from runtime.MemStats): 205 MB
> 
> 
> With Pure Go (time.Sleep()):
> Memory Usage: 14 MB
> Threads: 14
> System Memory (Sys from runtime.MemStats): 24 MB
> Additional Attempt
> I tried forcing thread cleanup using runtime.LockOSThread() and 
> runtime.Goexit(), but while the number of threads decreases, memory is still 
> never fully released:
> 
> go func() { runtime.LockOSThread() defer wg.Done() C.cgoSleep() 
> runtime.Goexit() }() Questions
> Why is memory increasing indefinitely with CGO?
> Why are threads not getting properly cleaned up after CGO calls?
> Is there a way to force the Go runtime to reclaim memory allocated for CGO 
> threads?
> Is there a better approach to handling CGO calls that spawn short-lived 
> threads?
> Would using runtime.UnlockOSThread() help in this case, or is this purely a 
> CGO threading issue?
> Is there a way to track down where the memory is being held? Since pprof does 
> not show high memory usage, what other tools can I use?
> Go Version 
> go1.23.5 darwin/arm64
> 
> -- 
> 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+unsubscr...@googlegroups.com 
> <mailto:golang-nuts+unsubscr...@googlegroups.com>.
> To view this discussion visit 
> https://groups.google.com/d/msgid/golang-nuts/5e8c1622-e6f0-47a8-a869-e78797800fb5n%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/golang-nuts/5e8c1622-e6f0-47a8-a869-e78797800fb5n%40googlegroups.com?utm_medium=email&utm_source=footer>.

-- 
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+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/golang-nuts/0628BDD7-D9AE-4F22-B5AA-8F0ACB873B98%40ix.netcom.com.

Reply via email to