Elixirで :"example_#{varialble}"
みたいなコードを見つけ「無尽蔵に叩かれるとGCから漏れるなあ」と思って確認した。
案の定GCから漏れるコードだった。
ErlangのatomはGC対象外なことは有名。
なのでString.to_atom
や:erlang.binary_to_atom
は危険。
最初に言及したコードもしっかりと:erlang.binary_to_atom
にトランスレートされる。
トランスレートされることの確認のためにbeamファイルをdisassembleしたので記録しておく。
逆アセコマンド
下のようなスクリプトを書いた。たまに使う気がしてgithubに起きました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
#! /usr/bin/env elixir
defmodule Disassemble do
@moduledoc false
@command __ENV__.file |> Path.basename()
@usage """
NAME:
#{@command} -- disassemble beam
SYNOPSIS:
#{@command} file
"""
def usage(), do: @usage
def run(path) do
result = :beam_lib.chunks(path, [:abstract_code])
{:ok, {_, [{:abstract_code, {_, ac}}]}} = result
IO.puts(:erl_prettypr.format(:erl_syntax.form_list(ac)))
end
end
if 0 < length(System.argv()) do
hd(System.argv())
|> to_charlist()
|> Disassemble.run()
else
IO.puts(Disassemble.usage())
end
|
調査対象
下のようなコードを書いて mix compile しました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
defmodule Example do
@existing_atom :example_existing
def interpolation(var) do
:"example_#{var}"
end
def use_string(var) do
String.to_atom("example_#{var}")
end
def use_string_for_existing(var) do
String.to_existing_atom("example_#{var}")
end
end
|
おしまい。気楽なのもあり道具の使い方のメモばっかしてて自己嫌悪に陥る。