跟踪Google App Engine Golang应用程序中的内存泄漏?

问题描述:

I saw this Python question: App Engine Deferred: Tracking Down Memory Leaks

... Similarly, I've run into this dreaded error:

Exceeded soft private memory limit of 128 MB with 128 MB after servicing 384 requests total

...

After handling this request, the process that handled this request was found to be using too much memory and was terminated. This is likely to cause a new process to be used for the next request to your application. If you see this message frequently, you may have a memory leak in your application.

According to that other question, it could be that the "instance class" is too small to run this application, but before increasing it I want to be sure.

After checking through the application I can't see anything obvious as to where a leak might be (for example, unclosed buffers, etc.) ... and so whatever it is it's got to be a very small but perhaps common mistake.

Because this is running on GAE, I can't really profile it locally very easily as far as I know as that's the runtime environment. Might anyone have a suggestion as to how to proceed and ensure that memory is being recycled properly? — I'm sort of new to Go but I've enjoyed working with it so far.

我看到了这个Python问题:延迟的App Engine:跟踪内存泄漏 p>

...类似,我遇到了这个可怕的错误 : p>

为总共384个请求提供服务后,超出了128 MB的软私有内存限制,即128 MB p> blockquote>

... p>

处理完此请求后,发现处理该请求的进程占用了太多内存,并被终止。 这很可能导致新过程用于您的应用程序的下一个请求。 如果您经常看到此消息,则可能是应用程序内存泄漏。 p> blockquote>

根据另一个问题,可能是“实例类”为 太小而无法运行此应用程序,但是在确定它之前,我想确定一下。 p>

在检查完该应用程序后,我看不到任何明显的泄漏可能出现的地方(例如 ,未关闭的缓冲区等)……所以无论是什么,它都必须是一个很小但可能是常见的错误。 p>

因为这是在GAE上运行的,所以我无法真正 据我所知,这是运行时环境,因此很容易在本地对其进行概要分析。 可能有人对如何继续进行操作并确保正确地回收内存提出建议吗? strong> —我对Go还是陌生的,但到目前为止我很喜欢使用它。 p> div>

For a starting point, you might be able to try pprof.WriteHeapProfile. It'll write to any Writer, including an http.ResponseWriter, so you can write a view that checks for some auth and gives you a heap profile. An annoying thing about that is that it's really tracking allocations, not what remains allocated after GC. So in a sense it's telling you what's RAM-hungry, but doesn't target leaks specifically.

The standard expvar package can expose some JSON including memstats, which tells you about GCs and the number allocs and frees of particular sizes of allocation (example). If there's a leak you could use allocs-frees to get a sense of whether it's large allocs or small that are growing over time, but that's not very fine-grained.

Finally, there's a function to dump the current state of the heap, but I'm not sure it works in GAE and it seems to be kind of rarely used.

Note that, to keep GC work down, Go processes grow to be about twice as large as their actual live data as part of normal steady-state operation. (The exact % it grows before GC depends on runtime.GOGC, which people sometimes increase to save collector work in exchange for using more memory.) A (very old) thread suggests App Engine processes regulate GC like any other, though they could have tweaked it since 2011. Anyhow, if you're allocating slowly (good for you!) you should expect slow process growth; it's just that usage should drop back down again after each collection cycle.

A possible approach to check if your app has indeed a memory leak is to upgrade temporarily the instance class and check the memory usage pattern (in the developer console on the Instances page select the Memory Usage view for the respective module version).

If the pattern eventually levels out and the instance no longer restarts then indeed your instance class was too low. Done :)

If the usage pattern keeps growing (with a rate proportional with the app's activity) then indeed you have a memory leak. During this exercise you might be able to also narrow the search area - if you manage to correlate the graph growth areas with certain activities of the app.

Even if there is a leak, using a higher instance class should increase the time between the instance restarts, maybe even making them tolerable (comparable with the automatic shutdown of dynamically managed instances, for example). Which would allow putting the memory leak investigation on the back burner and focusing on more pressing matters, if that's of interest to you. One could look at such restarts as an instance refresh/self-cleaning "feature" :)