我正在写一个Go网络服务器,它将Server-Sent Events发送给一大堆客户端。我希望它支持成千上万的同时连接。这是我的代码(它只是保持连接打开并发送keep-alive事件):
func handleTest(w http.ResponseWriter, r *http.Request) {
h := w.Header()
h.Set("Content-Type", "text/event-stream; charset=utf-8")
h.Set("Cache-Control", "no-cache, no-store, must-revalidate")
h.Set("Connection", "keep-alive")
flusher := w.(http.Flusher)
notifier := w.(http.CloseNotifier)
flusher.Flush()
// Just send keep-alives.
keepAliveTime := 5 * time.Second
keepAlive := time.NewTimer(keepAliveTime)
defer keepAlive.Stop()
for {
select {
case <-notifier.CloseNotify():
// The connection has been closed.
return
case <-keepAlive.C:
if _, err := io.WriteString(w, "event: keep-alive\ndata: null\n\n"); err != nil {
log.Println(err)
return
}
flusher.Flush()
keepAlive.Reset(keepAliveTime)
}
}
}
通过1000个连接,Windows报告每个连接使用大约70 kB的RAM。如果我添加了我实际正在做的所有内容(还有另一个goroutine,以及一些次要的事件编码函数),它每个连接都会增加到300 kB。这看起来很多。这里有1000个连接是pprof heap
所说的:
14683.25kB of 14683.25kB total ( 100%)
Dropped 12 nodes (cum <= 73.42kB)
Showing top 10 nodes out of 23 (cum >= 512.19kB)
flat flat% sum% cum cum%
11091.50kB 75.54% 75.54% 11091.50kB 75.54% io.copyBuffer
2053kB 13.98% 89.52% 2053kB 13.98% net/http.newBufioWriterSize
514kB 3.50% 93.02% 514kB 3.50% net/http.newBufioReader
512.56kB 3.49% 96.51% 512.56kB 3.49% runtime.makeslice
512.19kB 3.49% 100% 512.19kB 3.49% net.newFD
0 0% 100% 11091.50kB 75.54% io.Copy
0 0% 100% 1540.19kB 10.49% main.main
0 0% 100% 512.19kB 3.49% net.(*TCPListener).AcceptTCP
0 0% 100% 512.19kB 3.49% net.(*netFD).accept
0 0% 100% 512.19kB 3.49% net.(*netFD).acceptOne
所以我有几个问题:
handleTest()
返回?这会节省我的记忆力还是http.ResponseWriter
对象中的所有内存使用?修改:对于3.看起来我可以使用Hijacker
编辑2 :我尝试使用Hijacker
重新实现它。它将每个连接的内存使用量减少到大约10 kB,这更合理!
答案 0 :(得分:1)
为什么pprof认为堆是14 MB,但Windows说内存使用量是70 MB?其余的是堆栈吗?
除了堆之外,还有Go运行时,堆栈和代码段。操作系统也可能分配超过实际需要的数量。另外,Windows报告的驻留内存量或OS内存分配的总量是多少?