簡體   English   中英

我的Google App Engine代碼中的內存泄漏

[英]Memory leak in my Google App Engine code

我有以下代碼試圖循環一個大表(~100k行; ~30GB)

def updateEmailsInLoop(cursor=None, stats={}):
    BATCH_SIZE=10
    try:
        rawEmails, next_cursor, more = RawEmailModel.query().fetch_page(BATCH_SIZE, start_cursor=cursor)
        for index, rawEmail in enumerate(rawEmails):
            stats = process_stats(rawEmail, stats)
        i = 0
        while more and next_cursor:
            rawEmails, next_cursor, more = RawEmailModel.query().fetch_page(BATCH_SIZE, start_cursor=next_cursor)
            for index, rawEmail in enumerate(rawEmails):
                stats = process_stats(rawEmail, stats)
            i = (i + 1) %100
            if i == 99:
                logging.info("foobar: Finished 100 more %s", str(stats))
        write_stats(stats)
    except DeadlineExceededError:
        logging.info("foobar: Deadline exceeded")
        for index, rawEmail in enumerate(rawEmails[index:], start=index):
            stats = process_stats(rawEmail, stats)
        if more and next_cursor:
            deferred.defer(updateEmailsInLoop, cursor = next_cursor, stats=stats, _queue="adminStats")

但是,我不斷收到以下錯誤:

在處理此請求時,發現處理此請求的進程使用了​​太多內存並被終止。 這可能會導致新進程用於您的應用程序的下一個請求。 如果經常看到此消息,則可能是應用程序中存在內存泄漏。

...有時....

在為9個請求提供服務后,超過128 MB的軟私有內存限制(154 MB)

我已經改變了我的代碼所以我總是只在任何給定的時間內輸入10個條目,所以我不知道為什么我仍然沒有內存不足?

有三種方法可以完成這種工作(在數據存儲區中對大量行進行迭代):

  1. 處理1批x實體並使用游標創建任務(推送隊列)。
  2. 處理1批x個實體並使用一些顯示進度的javascript響應瀏覽器並將window.location更改為包含游標和當前進度的鏈接。 (這是我的首選方法)
  3. 使用mapreduce(代碼更難)(但可以應用於10M-1B行)

對於我需要的大多數應用程序,x通常在100-500之間。 這是我用於迭代超過1.5m-2m行的代碼,以生成一些報告或更新我的數據庫中的內容。 對於報告,我保存包含csv格式所需信息的實體,最后,我讀取所有實體,合並它們並刪除它們。 (這樣做是為了生成1.5m行的excel數據)(它是java,但應該很容易翻譯成python):

 resp.getWriter().println("<html><head>");
 resp.getWriter().println(
                    "<script type='text/javascript'>function f(){window.location.href='/do/convert/" + this.getClass().getSimpleName() + "?cursor=" + cursorString + "&count="
                            + count + "';}</script>");
 resp.getWriter().println("</head><body onload='f()'>");
 resp.getWriter().println(
                    "<a href='/do/convert/" + this.getClass().getSimpleName() + "?cursor=" + cursorString + "&count=" + count + "'>Next page -->" + cursorString + " </a>");
 resp.getWriter().println("</body></html>");

如果您的“進度”很大且很混亂,請將其保存在實體中(一個或多個,取決於您正在做的事情)如果您正在執行任務版本,我建議您使用任務名稱或使您的任務具有冪等性(特別是如果你的計數東西)。 如果你的計數東西,我建議保存包含你正在計數的實體的密鑰的實體,並在最后計算這些。

暫無
暫無

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

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