Thanks for the response Robert, 

I tried to put a semaphore to control the max amount CGO calls 
simultaneously,
similar to what they did here 
https://github.com/golang/go/blob/master/src/net/net.go#L794-L818

i noticed it does help somewhat, but memory consumption keeps going up 
uncontrollably.



I tried to do LockOSThread and use GoExit so the thread will close. 
it indeed closes the thread but the memory is never released back to the os.

is there a way i can force it to release the resources back to the os when 
the thread is closed?
ב-יום שלישי, 4 במרץ 2025 בשעה 22:32:45 UTC+2, robert engels כתב/ה:

> Or at the github issue points out, if the thread will exit, LockOSThread 
> my work.
>
> On Tuesday, March 4, 2025 at 2:23:28 PM UTC-6 robert engels wrote:
>
>> One way you can address this is to put a semaphore on the Go side around 
>> the C call, so you ensure only so many C calls are made simultaneously.
>>
>>
>> On Mar 4, 2025, at 1:26 PM, David Bell <davidbe...@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* 
>>    
>>    1. *Why is memory increasing indefinitely with CGO?* 
>>    2. *Why are threads not getting properly cleaned up after CGO calls?* 
>>    3. *Is there a way to force the Go runtime to reclaim memory 
>>    allocated for CGO threads?* 
>>    4. *Is there a better approach to handling CGO calls that spawn 
>>    short-lived threads?* 
>>    5. *Would using runtime.UnlockOSThread() help in this case, or is 
>>    this purely a CGO threading issue?* 
>>    6. *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...@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/9a40383e-5b47-4f2b-bdea-a50946381650n%40googlegroups.com.

Reply via email to