【问题标题】:How to free memory allocated for some structure in Crystal - manually?如何释放为 Crystal 中的某些结构分配的内存 - 手动?
【发布时间】:2018-11-19 07:55:08
【问题描述】:

我有一个基于 Kemal 的 RESTful Web 服务,它返回“非常大”(大小从 10 到 17M)的 JSON 数据块,这些数据是由 to_json 方法从“大”哈希结构生成的。

根据 GC 警告消息,我的代码“可能导致内存泄漏”,而我自己的测量结果表明内存在应用程序运行时“泄漏”。

所以,我认为,手动释放为 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

附:我在每个用户请求之后插入了执行 GC.collect 的 after_all 钩子。不知道,也许这可以解决我的问题(但我认为这根本不是正确的方法)。

UPD:在我将 GC.collect 添加到 after_all Kemal 挂钩之后 - 内存泄漏消失了。但是全局 GC.collect 可能太慢了,而且据我所知,它会阻塞所有光纤和 socket.accept()。如果我弄错了,请告诉我。

【问题讨论】:

标签: memory-leaks crystal-lang kemal


【解决方案1】:

是的,您不应在每次请求后致电 GC.collect

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

【讨论】:

  • 谢谢,Johannes,我从来没有使用过 to_json 的可选参数,也不记得了。我最近都应用了您的解决方案,并且必须写评论,它是如何工作的。使用缓冲 IO 模拟可能会提高我的 Web 服务的性能真是太好了:它现在非常强大,但如果它可以以闪电般的速度运行 - 那真是太棒了!我将投票支持您的答案作为决议,再次感谢您!
  • 是的,它有效!我已经删除了 GC.collect 和 after_all 钩子 - 我看到通过 to_json(io : IO) 序列化直接到 env.response (实现 IO 接口)没有内存泄漏。这是一个很棒的答案,谢谢!
猜你喜欢
  • 2016-09-22
  • 2014-05-21
  • 1970-01-01
  • 2022-10-14
  • 1970-01-01
  • 2017-05-07
  • 1970-01-01
  • 2021-08-07
  • 2019-09-10
相关资源
最近更新 更多