Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have a Kemal-based RESTful web service that returns "very big" (from 10 to 17M in size) chunks of JSON data, which is produced by to_json method from the "big" Hash structure.

According to GC warning messages my code "may lead to memory leaks" and my own measurements show that memory is "leaking" during application runtime.

So, i think, it will be good to free memory allocated for the Hash and it's JSON string representation by hand, but i dont know how to do this: my experiments with bad-documented GC.free method was not succesful and i don't know in what direction to continue my investigations...

Please, tell me what can i do to avoid memory leaks?

You can look at the not-very-fresh-but-generally-actual version of my very simple application (actually it was developed inside the closed corporate network segment) here https://github.com/DRVTiny/Druid/blob/master/src/druid_mp.cr

Code that leads to memory leaks:

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. I've inserted after_all hook executing GC.collect after each user request. Dont know, maybe this can solve my problem (but i think this is not the right way at all).

UPD: After i've added GC.collect to after_all Kemal hook - memory leaks dissapears. But global GC.collect probably too slow and, as i know, it blocks all fibers and socket.accept(). Please, let me know if i've mistaken.

like image 411
drvtiny Avatar asked Jun 09 '18 12:06

drvtiny


1 Answers

Yes, you shouldn't call GC.collect after each request.

Apart from improvements to the GC (which will come eventually), the easiest shot is to avoid the useless string allocation. Judging by your example code, you don't need the result from tha to_json call in memory as a string. You can just serialise it directly to the IO stream like to_json(env.response). This is faster over all and doesn't allocate additional memory, completely avoiding the issue with releasing memory.

like image 190
Johannes Müller Avatar answered Sep 20 '22 16:09

Johannes Müller