簡體   English   中英

Google App Engine Go內存管理

[英]Google App Engine Go memory management

我最近遇到了一個問題,App Engine會終止我的Go實例,因為它說內存不足。 實例的內存限制設置為128Mb。

但是,我無法確定所有內存的分配位置。 當我運行以下代碼時:

var s runtime.MemStats
runtime.ReadMemStats(&s)
c.Debugf("allocated memory: %d", s.Alloc)

它告訴我,當分配的內存達到大約39-40Mb時,我的應用程序因以下錯誤而終止:

服務1個請求后超過135.082 MB的軟私有內存限制

類似地,當runtime.ReadMemStats(&s)表明我使用的是20 Mb時,App Engine控制台顯示我的實例正在使用92Mb。 重做相同的請求, runtime.ReadMemStats(&s)仍然顯示20Mb,而App Engine控制台顯示119Mb。

我已經禁用appstats ,仍然沒有幫助。

我的大部分內存被內存緩存耗盡,我可以減少它以適應約束(或增加我的實例的內存限制),但我想知道所有內存的使用位置 如果有人可以對此有所了解,或者如何在App Engine上正確分析內存使用情況,那將會有很大幫助。

更新:設法在本地重現此。

以下是一個示例應用程序,它在一個請求中分配一些整數,垃圾在下一個請求中收集它們:

// Package test implements a simple memory test for Google App Engine.
package test

import (
    "net/http"
    "runtime"

    "appengine"
)

var buffer []int64

func init() {
    http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
    var s runtime.MemStats
    c := appengine.NewContext(r)
    if len(buffer) == 0 {
        // Allocate 2^22 integers.
        runtime.ReadMemStats(&s)
        c.Debugf("Memory usage: %d bytes (%d system).", s.Alloc, s.Sys)
        buffer = make([]int64, 4*1024*1024)
        for i, _ := range buffer {
            buffer[i] = int64(i*i)
        }
        runtime.ReadMemStats(&s)
        c.Debugf("Memory usage increased to: %d bytes (%d system).", s.Alloc, s.Sys)
    } else {
        // Remove all references to the slice pointed to by buffer.
        // This should mark it for garbage collection.
        runtime.ReadMemStats(&s)
        c.Debugf("Memory usage: %d bytes (%d system).", s.Alloc, s.Sys)
        buffer = nil
        runtime.GC()
        runtime.ReadMemStats(&s)
        c.Debugf("After GC event: %d bytes (%d system).", s.Alloc, s.Sys)
    }
    w.WriteHeader(http.StatusTeapot)
}

使用開發服務器運行時:

$ ./go_appengine/dev_appserver.py test

2013/09/16 12:28:28 DEBUG: Memory usage: 833096 bytes (272681032 system).
2013/09/16 12:28:28 DEBUG: Memory usage increased to: 34335216 bytes (308332616 system).
INFO     2013-09-16 12:28:28,884 module.py:593] default: "GET / HTTP/1.1" 418 -
2013/09/16 12:28:29 DEBUG: Memory usage: 34345896 bytes (308332616 system).
2013/09/16 12:28:29 DEBUG: After GC event: 781504 bytes (308332616 system).
INFO     2013-09-16 12:28:29,560 module.py:593] default: "GET / HTTP/1.1" 418 -
2013/09/16 12:28:30 DEBUG: Memory usage: 791616 bytes (308332616 system).
2013/09/16 12:28:30 DEBUG: Memory usage increased to: 34337392 bytes (308332616 system).
INFO     2013-09-16 12:28:30,276 module.py:593] default: "GET / HTTP/1.1" 418 -
2013/09/16 12:28:36 DEBUG: Memory usage: 34347536 bytes (308332616 system).
2013/09/16 12:28:36 DEBUG: After GC event: 783632 bytes (308332616 system).
INFO     2013-09-16 12:28:36,224 module.py:593] default: "GET / HTTP/1.1" 418 -

看來內存分配和垃圾收集工作正常。 但是,查看ps輸出,似乎釋放內存不會減少進程的虛擬內存使用量:

$ ps axo command,vsize,rss | ag go_app
/usr/bin/python2.7 ./go_app 381248 56608
$ ps axo command,vsize,rss | ag go_app
/usr/bin/python2.7 ./go_app 676324 57652
$ ps axo command,vsize,rss | ag go_app
/usr/bin/python2.7 ./go_app 750056 57856
$ ps axo command,vsize,rss | ag go_app
/usr/bin/python2.7 ./go_app 750056 57856

似乎運行底層Go實例的Python進程不斷增長其虛擬內存,但它永遠不會被釋放。 似乎在生產服務器上發生類似的事情:實例運行時報告的分配內存與內核報告的已用內存不同。

正如@Kluyg所建議的那樣,管理控制台似乎顯示了系統分配的內存 ,這是有道理的。

根據文檔, Alloc字段顯示已分配且仍在使用的字節。 但是,在垃圾收集語言中,當GC釋放內存時,它不會立即返回系統(可以很快再次請求,所以為什么還要回來呢?)。 所以你真正需要監視的是Sys字段,它計算從系統獲得的字節數。 您可能對本文感興趣,並提供了一些如何最大限度地減少內存使用量的見解。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM