memory-leaks - 如何释放为 Crystal 中的某些结构分配的内存 - 手动?
问题描述
我有一个基于 Kemal 的 RESTful Web 服务,它返回“非常大”(从 10 到 17M 大小)的 JSON 数据块,这些数据是由“大”哈希结构中的 to_json 方法生成的。
根据 GC 警告消息,我的代码“可能导致内存泄漏”,而我自己的测量结果表明内存在应用程序运行时“泄漏”。
所以,我认为,手动释放为哈希分配的内存和它的 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
PS 我在每个用户请求之后插入了 after_all 钩子执行 GC.collect 。不知道,也许这可以解决我的问题(但我认为这根本不是正确的方法)。
UPD:在我将 GC.collect 添加到 after_all Kemal 钩子之后 - 内存泄漏消失了。但是全局 GC.collect 可能太慢了,而且据我所知,它会阻塞所有光纤和 socket.accept()。请让我知道我是否弄错了。
解决方案
是的,您不应该GC.collect
在每次请求后致电。
除了对 GC 的改进(最终会出现)之外,最简单的方法是避免无用的字符串分配。从您的示例代码来看,您不需要将to_json
内存中调用的结果作为字符串。您可以直接将其序列化为 IO 流,例如to_json(env.response)
. 这总体上更快,并且不分配额外的内存,完全避免了释放内存的问题。
推荐阅读
- php - 自定义 Woocommerce 结帐字段在页面加载后恢复为默认值
- ruby-on-rails - Rails - 多个线程以避免松弛的 3 秒 API 响应规则
- java - 为什么我找不到迭代器的值?
- python - 根据各列的 True 或 False 值过滤行
- python - Python 文件未附加在 Raspberry Pi 上
- python - 类型不正确。预期的 pk 值,在 DRF 中收到 str。(一对一字段)
- css - CSS:将最大高度设置为与“无”最大高度时高度相同的值?
- google-cloud-platform - Cloud Run 服务间通信
- google-sheets - 使用 INDIRECT、INDEX 和 MATCH 的参考表的条件格式?
- javascript - 如何使用参数检查是否在 Firebase 中验证了电子邮件?