2

Erlang コードを書いているときに、理解できない奇妙な状況に遭遇しました。

コード:

-module(recursive_test).
-export([a/2]).

a(_, []) -> ok;
a(Args, [H|T]) ->
    F = fun() -> a(Args, T) end,
    io:fwrite(
        "~nH: ~p~nStack Layers: ~p",
        [H, process_info(self(), stack_size)]
    ),
    b(Args, F).

b(Args, F) ->
    case Args of
        true -> ok;
        false -> F()
    end.

出力:

(Erlang/OTP 20)
12> c(recursive_test).
{ok,recursive_test}
13> recursive_test:a(false, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).
H: 1
Stack Layers: 28
H: 2
Stack Layers: 28
H: 3
Stack Layers: 28
H: 4
Stack Layers: 28
H: 5
Stack Layers: 28
H: 6
Stack Layers: 28
H: 7
Stack Layers: 28
H: 8
Stack Layers: 28
H: 9
Stack Layers: 28
H: 10
Stack Layers: 28
ok
14> recursive_test:a(false, [1, 2, 3, 4, 5, 6]).
H: 1
Stack Layers: 28
H: 2
Stack Layers: 28
H: 3
Stack Layers: 28
H: 4
Stack Layers: 28
H: 5
Stack Layers: 28
H: 6
Stack Layers: 28
ok

この記事から私が理解していることから、Erlang は Last Call Optimization を使用します。関数が最後に行うことが別の関数を呼び出すことである場合、BeamVM は代わりに、新しいスタックをプッシュする代わりに、プログラム カウンターを新しい関数の先頭にジャンプします。フレーム。これは、上記のようなパターンでは、スタックではなくヒープを処理していることを意味するのでしょうか? これにより、これらの関数で以前に保持されていメモリが解放されますか?時間)?このパターンを使用すると、(明らかなデバッグの苦労以外に) 悪影響はありますか?

4

2 に答える 2

2

まず、fun(ラムダ、クロージャー、またはあなたがそれを呼びたいものは何でも)Erlangの不変の性質により、タプルのように想像できる方法で実装される可能性があり、実装されています

{fun, {Module, FuncRef, Arity, CodeVersion}, CapturedValues}

あなたの場合、それは次のようになります

{fun, {recursive_test, '-a/2-fun-0-', 2, 2248400...}, [false, [2,3,4|...]]}

funプラス 2 のキャプチャ値のアリティ 0 があるため、アリティが 2 であることに注意してください。

そうすれば、コードで何が起こっているのかを理解しやすくなります。真のタプルではなく、データの消費、ヒープ用語の参照、GC、Erlang ディストリビューション プロトコルでの転送などに関して非常によく似た動作をする構造であることを思い出してください。

F()これにより、内部での呼び出しb/2は次のようなものであるという2番目のことを理解できます

recursive_test:'-a/2-fun-0-'(false, [2,3,4|...])

これはナイスなテールコール、別名ジャンプです。したがって、コードはfun「タプル」を作成してから、コードをジャンプするだけです。その後、各fun「タプル」は参照されなくなるため、いつでも GCed できます。リストの代わりに数字で試してみることをお勧めします。より大きな数字を試し、process_info またはobserver を使用してメモリ消費を監視することをお勧めします。いい運動になるでしょう。

ところで、使用できます

process_info(self(), stack_size)

遅くて醜いのではなく

roplists:get_value(stack_size, process_info(self()))
于 2018-08-31T06:37:47.587 に答える