I am using goroutines in a package where there is a tcp server. The response most of the time is very heavy, but when the routines end it is not cleared from the memory.
func Handle() {
service := ":7777"
tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
checkError(err)
listener, err := net.ListenTCP("tcp", tcpAddr)
checkError(err)
defer listener.Close()
for {
conn, err := listener.Accept()
checkError(err)
go handleRequest(conn, db)
}
}
func handleRequest(conn net.Conn, db *sql.DB) {
message := make([]byte, 0, 4096)
tmp := make([]byte, 256)
n, err := conn.Read(tmp)
if err != nil {
if err != io.EOF {
fmt.Println("read error:", err)
}
}
message = append(message, tmp[:n]...)
fmt.Println("Message Received:", string(message))
// do something to get resp
conn.Write(append(resp, []byte("\n")...))
conn.Close()
debug.FreeOSMemory()
return
}
So in this case the response is big, and a goroutine using 10% of the memory, thats okay, because I'm getting 170.000 users from the database and parse the result to JSON. But when the handleRequest and it is still in the memory, if I'm not using debug.FreeOsMemory()
. I have doubts it is a good way to do it because it is in the debug pacakge so my question is it a good way to empty the memory what the goroutines are using? I tested it so it is not affected to the system and working very well. If not, what is the good way? I can't wait the GC for clear it up?! I read this and this is why I started to use it, in the first answer there is the last suggestion.
The Go runtime does not release free memory back to the OS "immediately", it would be inefficient. Read more about it here: Golang - Cannot free memory once occupied by bytes.Buffer.
You should let the Go runtime handle this. If your app is unstable without calling debug.FreeOsMemory()
, there are bigger problems which you shouldn't cover up with this even if it "seemingly" helps. It may even make things worse, as if serving a request does require a large amount of memory (which is properly freed by the GC when done with the request), calling FreeOsMemory()
will just return it to the OS which the runtime will have to ask for / allocate again when serving another request. Should you have not handed it back to the OS, it would be available for the next request...
Try to decrease the memory requirement of the request handler. If it is not possible (questionable), then limit the number of requests requiring large memory that may be served concurrently.
See this question+answer how to do that: Process Management for the Go Webserver
Also: Is this an idiomatic worker thread pool in Go?
As an alternative to occasionally invoking debug.FreeOsMemory()
, you can control the aggressiveness of the garbage collector with the GOGC
environment variable or with the debug.SetGCPercent()
method.
Empirically, I've seen that with a value as low as 10, it does its job.
See Package runtime
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With