{"action":"created","issue":{"url":"https://api.github.com/repos/manastech/crystal/issues/1646","labels_url":"https://api.github.com/repos/manastech/crystal/issues/1646/labels{/name}","comments_url":"https://api.github.com/repos/manastech/crystal/issues/1646/comments","events_url":"https://api.github.com/repos/manastech/crystal/issues/1646/events","html_url":"https://github.com/manastech/crystal/issues/1646","id":108913440,"number":1646,"title":"GC collects local variables in --release builds","user":{"login":"pgkos","id":11692818,"avatar_url":"https://avatars.githubusercontent.com/u/11692818?v=3","gravatar_id":"","url":"https://api.github.com/users/pgkos","html_url":"https://github.com/pgkos","followers_url":"https://api.github.com/users/pgkos/followers","following_url":"https://api.github.com/users/pgkos/following{/other_user}","gists_url":"https://api.github.com/users/pgkos/gists{/gist_id}","starred_url":"https://api.github.com/users/pgkos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pgkos/subscriptions","organizations_url":"https://api.github.com/users/pgkos/orgs","repos_url":"https://api.github.com/users/pgkos/repos","events_url":"https://api.github.com/users/pgkos/events{/privacy}","received_events_url":"https://api.github.com/users/pgkos/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/manastech/crystal/labels/bug","name":"bug","color":"fc2929"},{"url":"https://api.github.com/repos/manastech/crystal/labels/compiler","name":"compiler","color":"fef2c0"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":12,"created_at":"2015-09-29T17:01:53Z","updated_at":"2015-10-01T20:46:39Z","closed_at":null,"body":"I have noticed that the GC collects reachable toplevel local variables (EDIT: not only toplevel, see comment below), but only when building using `crystal build --release`. This causes problems when using native libraries (bindings).\r\n\r\nThe example is unfortunately quite complicated (sorry!). It uses the CrSFML library, but the problem should manifest itself while using other libraries too.\r\n\r\n```crystal\r\nrequire \"crsfml\"\r\n\r\nwindow = SF::RenderWindow.new(\r\n  SF.video_mode(400, 600), \"Title\", style: SF::Titlebar | SF::Close\r\n)\r\n\r\nwindow.framerate_limit = 60\r\n\r\n                          # replace with any valid local font path:\r\nfont = SF::Font.from_file(\"/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-L.ttf\")\r\ntext_field = SF::Text.new(\"foo\", font)\r\ntext_field.color = SF::Color::White\r\n\r\nwhile window.open?\r\n  # puts font  # uncommenting this line fixes the problem!\r\n  window.clear SF::Color::Black\r\n  window.draw text_field  # crash, \"font\" variable just got collected by the GC!\r\n  window.display\r\n  GC.collect  # to speed up the crash (segmentation fault)\r\nend\r\n```\r\nAs I have determined by debugging using `gdb`, inside the `while` loop the `font` variable is somehow treated as unreachable and gets collected by the garbage collector. As the `font` object contains a `@this` field which is a pointer to the native `sf::Font` C++ object, the native object also gets collected and that causes the segmentation fault inside the C++ SFML method `sf::Font::getTexture(int)`. That C++ method is invoked while drawing the text on the window.\r\n\r\nPutting the `font` variable into use inside the loop (e.g. `puts font`) **completely fixes the problem**.\r\n\r\nInterestingly, wrapping everything inside a class also fixes the problem, **but only when using instance variables**:\r\n```crystal\r\nrequire \"crsfml\"\r\n\r\nclass MainClass\r\n  def initialize\r\n    @window = SF::RenderWindow.new(\r\n      SF.video_mode(400, 600), \"Title\", style: SF::Titlebar | SF::Close\r\n    )\r\n    @window.framerate_limit = 60\r\n    @font = SF::Font.from_file(\r\n      \"/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-L.ttf\")\r\n    @text_field = SF::Text.new(\"foo\", @font)\r\n    @text_field.color = SF::Color::White\r\n  end\r\n\r\n  def run\r\n    while @window.open?\r\n      @window.clear SF::Color::Black\r\n      @window.draw @text_field\r\n      @window.display\r\n      GC.collect  # does not crash\r\n    end\r\n  end\r\nend\r\n\r\nmainobject = MainClass.new\r\nmainobject.run\r\n```"},"comment":{"url":"https://api.github.com/repos/manastech/crystal/issues/comments/144843388","html_url":"https://github.com/manastech/crystal/issues/1646#issuecomment-144843388","issue_url":"https://api.github.com/repos/manastech/crystal/issues/1646","id":144843388,"user":{"login":"asterite","id":209371,"avatar_url":"https://avatars.githubusercontent.com/u/209371?v=3","gravatar_id":"","url":"https://api.github.com/users/asterite","html_url":"https://github.com/asterite","followers_url":"https://api.github.com/users/asterite/followers","following_url":"https://api.github.com/users/asterite/following{/other_user}","gists_url":"https://api.github.com/users/asterite/gists{/gist_id}","starred_url":"https://api.github.com/users/asterite/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/asterite/subscriptions","organizations_url":"https://api.github.com/users/asterite/orgs","repos_url":"https://api.github.com/users/asterite/repos","events_url":"https://api.github.com/users/asterite/events{/privacy}","received_events_url":"https://api.github.com/users/asterite/received_events","type":"User","site_admin":false},"created_at":"2015-10-01T20:46:39Z","updated_at":"2015-10-01T20:46:39Z","body":"For the specific case of crsfml, it seems that when you assign a font to a text, the text becomes the owner of it, so font shouldn't be released. Or maybe font needs to have some sort of reference counting (incremented when assigned to another crsfml object, decremented when the GC collects it or collects another object that has a reference to the font). I faced a similar issue with LLVM, where it seems that once you create a JIT compiler you can't dispose the module: you must only dispose the JIT. I fixed it [like this](https://github.com/manastech/crystal/blob/master/src/llvm/jit_compiler.cr#L5).\r\n\r\nI know I mentioned ownership and reference counting, but these are issues that appear in Crystal only because they are also issues in C. There are ways to solve them while still having a GC (as I've done), so please don't suggest adding ARC, lifetimes or ownership to Crystal :-)"}}