我们编写了最简单的TCP服务器(带有次要日志记录)来检查内存占用(请参阅下面的tcp-server.go)
服务器只接受连接而不执行任何操作.它运行在Ubuntu 12.04.4 LTS服务器(内核3.2.0-61-generic)上,Go版本为go1.3 linux/amd64.
附加的基准测试程序(pulse.go)在此示例中创建10k连接,在30秒后断开它们,重复此循环三次,然后连续重复1k连接/断开的小脉冲.用于测试的命令是./pulse -big = 10000 -bs = 30.
第一个附加图是通过记录runtime.ReadMemStats获得的,当客户端数量已经改变了500的倍数时,第二个图形是服务器进程的"顶部"看到的RES内存大小.
服务器的内存可以忽略不计1.6KB.然后,内存由10k连接的"大"脉冲设置在~60MB(如上图所示),或者由ReadMemStats看到的大约16MB"SystemMemory".正如预期的那样,当10K脉冲结束时,使用中的内存会下降,最终程序开始将内存释放回OS,如灰色的"释放内存"行所示.
问题是系统内存(相应地,"顶部"看到的RES内存)从未显着下降(尽管它下降了一点,如第二张图所示).
我们可以预期,在10K脉冲结束后,内存将继续释放,直到RES大小是处理每个1k脉冲所需的最小值(由"top"看到的是8m RES,运行时报告的是2MB在使用中.ReadMemStats ).相反,RES保持在大约56MB,并且在使用中永远不会从最高值60MB下降.
我们希望确保不规则流量的可扩展性,偶尔会出现峰值,并且能够在不同时间出现峰值的同一个盒子上运行多个服务器.有没有办法有效地确保在合理的时间范围内尽可能多地将内存释放回系统?


代码https://gist.github.com/eugene-bulkin/e8d690b4db144f468bc5:
server.go:
package main
import (
"net"
"log"
"runtime"
"sync"
)
var m sync.Mutex
var num_clients = 0
var cycle = 0
func printMem() {
var ms runtime.MemStats
runtime.ReadMemStats(&ms)
log.Printf("Cycle #%3d: %5d clients | System: %8d Inuse: %8d Released: %8d Objects: %6d\n", cycle, num_clients, ms.HeapSys, ms.HeapInuse, ms.HeapReleased, ms.HeapObjects)
}
func handleConnection(conn net.Conn) {
//log.Println("Accepted connection:", conn.RemoteAddr())
m.Lock()
num_clients++
if …Run Code Online (Sandbox Code Playgroud) 我正在使用以下功能下载小于20MB的文件.它将整个内容读取到内存中,因为另一个函数必须在将字节写入磁盘之前对字节执行操作.
func getURL(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("getURL: %s", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("getURL: %s", err)
}
return body, nil
}
Run Code Online (Sandbox Code Playgroud)
这样可以正常工作,但系统会消耗所有内存.
是否可以释放body由其他函数处理后使用的内存,因此内存使用量不会大于当前正在处理的字节数?