此后不久,内存再次达到峰值Erlang gc(fullsweep)?

ds97pgxw  于 2022-12-08  发布在  Erlang
关注(0)|答案(1)|浏览(197)

当Erlang全扫描时,内存会立即下降,但在很短的时间内它会上升到原来的峰值,然后下降。
当我在将gc转换为TestPid 3分钟或更长时间后停止循环以创建内存时。内存会上升到最初的峰值,然后在我开始循环后下降。
它是如何工作的?

这是我的简单测试代码。
ts.erl

-module(ts).
-behaviour(gen_server).
%% API
-export([
    start/0,
    stop/0,
    gc/0, loop_cnt/1
]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
    terminate/2, code_change/3]).

-define(SERVER, ?MODULE).
-define(BASE_CNT, 10000).
-define(ONE_LOOP_CNT, 200).
-record(state, {loop_cnt = 0, one_loop_cnt = 0}).

start() ->
    gen_server:start({local, ?SERVER}, ?MODULE, [], []).

stop() ->
    gen_server:cast(?SERVER, stop).

gc() ->
    gen_server:cast(?SERVER, gc).

loop_cnt(Cnt) when is_number(Cnt) ->
    gen_server:cast(?SERVER, {loop_cnt, Cnt}).

init([]) ->
    io:format("start mem ~n"),
    erlang:send_after(1, self(), start_add_mem),
    {ok, #state{one_loop_cnt = ?ONE_LOOP_CNT}, 0}.

handle_call(_Req, _From, State) ->

    {noreply, State}.

handle_cast(start_add_mem, State) ->
    io:format("cast start_add_mem~n"),
    {noreply, State};

handle_cast(gc, State) ->
    io:format("garbage_info beforegc ~w ~n", [erlang:process_info(self(), garbage_collection)]),
    {Us, _} = timer:tc(erlang, garbage_collect, [self()]),
    io:format("do_gc cost:~wms ~n", [Us / 1000]),
    {noreply, State};

handle_cast({loop_cnt, Cnt}, State) ->
    io:format("set loop_cnt ~w ~n", [Cnt]),
    {noreply, State#state{one_loop_cnt = Cnt}};

handle_cast(stop, State) ->
    {stop, normal, State}.

handle_info(start_add_mem, #state{loop_cnt = Cnt, one_loop_cnt = OneLoopCnt} = State) ->
    erlang:send_after(1000, self(), start_add_mem),
    StartCnt = Cnt rem 100,
    case Cnt rem 30 =:= 0 of
        true ->
            io:format("garbage_info ~w ~n", [erlang:process_info(self(), garbage_collection)]);
        false ->
            ok
    end,
    do_add_mem(StartCnt, OneLoopCnt),
    try
        {_, L} = erlang:process_info(self(), garbage_collection),
        case lists:keyfind(minor_gcs, 1, L) of
            false ->
                io:format("gc find mingcs error~w ~n", [erlang:process_info(self(), garbage_collection)]);
            {_, GcCount} ->
                case GcCount =:= 0 of
                    true ->
                        io:format("mabay_trigger gc ~w ~n", [erlang:process_info(self(), garbage_collection)]);
                    _ ->
                        ok
                end
        end
    catch _A:_B ->
        io:format("gc print error ~w ~w ~n", [erlang:process_info(self(), garbage_collection), {_A, _B}]),
        ok
    end,
    {noreply, State#state{loop_cnt = Cnt + 1}};

handle_info(_Req, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%%===================================================================
%%% Internal functions
%%%===================================================================

do_add_mem(StartCnt, OneLoopCnt) ->

    lists:foreach(
        fun(I) ->
            Dict = dict:new(),
            NewDict = lists:foldl(
                fun(J, AccDict) ->
                    dict:store(J, I, AccDict)
                end, Dict, lists:seq(1, OneLoopCnt)),
            L = lists:seq(1, OneLoopCnt),
            case random:uniform() > 0.5 of
                true ->
                    erlang:put({tm, I}, {NewDict, L});
                false ->
                    erlang:put({tm, I}, undefined)
            end
        end, lists:seq(StartCnt * ?BASE_CNT, StartCnt * ?BASE_CNT + ?BASE_CNT)),
    ok.
qni6mghb

qni6mghb1#

我认为峰值是GC在运行主要GC时创建新堆,第二个谷值是释放前一个堆的时候。
考虑到每个进程在不同的时间执行其GC,并且您通常没有具有5GB堆的进程,您不会(或者不应该)在生产系统中注意到它。
关于Erlang的世代GC的文档非常详细,我认为它值得仔细阅读。
此外,您还可以使用trace在GC开始或结束时获取消息:或者使用process_infototal_heap_sizeheap_size

相关问题