如何手动释放为 Crystal 中的某些结构分配的内存?

How to free memory allocated for some structure in Crystal - manually?

我有一个基于 Kemal 的 RESTful Web 服务,其中 returns "very big"(大小从 10 到 17M)块 JSON 数据,由to_json 方法来自 "big" 哈希结构。

根据 GC 警告消息,我的代码 "may lead to memory leaks" 和我自己的测量显示在应用程序运行期间内存为 "leaking"。

所以,我认为,释放分配给哈希的内存会很好,它是手动 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()。如果我弄错了,请告诉我。

是的,您不应该在每次请求后调用 GC.collect

除了对 GC 的改进(最终会出现)之外,最简单的方法是避免无用的字符串分配。从您的示例代码来看,您不需要 to_json 在内存中调用的结果作为字符串。您可以直接将它序列化到 IO 流,如 to_json(env.response)。这总体上更快,并且不分配额外的内存,完全避免了释放内存的问题。