我有一个基于Kemal的RESTful Web服务,可以返回"非常大的" (大小从10到17M)JSON数据块,由大约"大"生成的to_json方法生成。哈希结构。
根据GC警告消息,我的代码"可能导致内存泄漏"而且我自己的测量结果表明记忆已经泄漏了#34;在应用程序运行时。
所以,我认为,为手机释放为Hash分配的内存和它的JSON字符串表示会很好,但我不知道如何做到这一点:我的实验与记录错误的GC.free方法没有成功,我不知道继续调查的方向......
请告诉我如何避免内存泄漏?
你可以在这里查看我非常简单的应用程序的非常新鲜但通常是实际版本(实际上它是在封闭的公司网络段内开发的)https://github.com/DRVTiny/Druid/blob/master/src/druid_mp.cr
导致内存泄漏的代码:
get "/service/:serviceid" do |env|
if (svcid = env.params.url["serviceid"]) && svcid.is_a?(String) && svcid =~ /^s?\d+$/
druid.svc_branch_get((svcid[0] == 's' ? svcid[1..-1] : svcid).to_i).to_json
else
halt env, status_code: 404, response: %q({"error": "Wrong service identificator"})
end
rescue ex
halt env, status_code: 503, response: {"error": "Unhandled exception #{ex.message}"}.to_json
end
P.S。我在每个用户请求后插入了执行GC.collect的after_all钩子。不知道,也许这可以解决我的问题(但我认为这根本不是正确的方法)。
UPD:在我将GC.collect添加到after_all Kemal钩子之后 - 内存泄漏消失了。但是全局GC.collect可能太慢了,据我所知,它会阻塞所有光纤和socket.accept()。如果我弄错了,请告诉我。
答案 0 :(得分:7)
是的,您不应在每次请求后致电GC.collect
。
除了改进GC(最终将会出现)之外,最简单的方法是避免无用的字符串分配。根据您的示例代码判断,您不需要将to_json
内存中的结果作为字符串调用。您可以直接将其序列化为IO流,如to_json(env.response)
。这比所有更快,并且没有分配额外的内存,完全避免释放内存的问题。