【问题标题】:erlang memory grow up when c:l file当c:l文件时erlang内存增长
【发布时间】:2018-09-15 13:14:18
【问题描述】:

我发现了一个问题,但我不确定这是错误还是其他,我不知道如何处理它。

一次我c:l(test_data)文件两次,发现关系进程的内存都变大了。 这是我的测试。

操作系统:linux 或 win

Erlang 版本:R19 或 R20

目录:erl_test

文件: test_server.erl,test_statem.erl,test_fsm.erl,test_data.erl,test_server2.erl。

test_data.erl 是大文件,1M。

操作是:

erl -s make all
erl
main:c(1).        %% will make 4 process: fsm , statem, server
observer:start(). %% open observer, see process memory
main:l().         %% will reload test_data.erl
                  %% look 4 processes memory
main:l().         %% reload test_data again 
                  %% look 4 processes memory, become large

main.erl 和 test_server.erl 代码:

%% main.erl
-module(main).
-export([c/1, l/0]).

%% make process
c(N) ->
    test_fsm:create_mon(N),
    test_statem:create_mon(N),
    test_server:create_mon(N),
    test_server2:create_mon(N),
    ok.

%% reload test_data
l()->
    c:l(test_data).

%% test_server.erl, test_fsm, test_statem's code the same as test_server
-module(test_server).
-behaviour(gen_server).
%% API
-export([start_link/0, create_mon/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {mon = undefined}).

create_mon(0) -> ok;
create_mon(N) -> 
    start_link(),
    create_mon(N-1).

start_link() ->
    gen_server:start(?MODULE, [], []).

init([]) ->
    erlang:send_after(10000, self(), init),
    {ok, #state{mon = test_data:get(1)}}.

...

handle_info(_Info, State) ->
    Mon = test_data:get(1),
    erlang:send_after(10000, self(), info),
    {noreply, State#state{mon = Mon}}.

...

%%test_data.erl
-module(test_data).
-export([get/1]).
-include("test.hrl").

get(1) ->
     #mon{id = 1,name = "test", kind = 10,boss = 0,type = 0,career = 0,color 
           = 1,auto = 0,icon = 5010011,icon_scale = 1,icon_effect = 
           "",icon_texture = 0,weapon_id = 5010011,foot_icon = 0,desc = 
           "",lv = 1,hp_lim = 1000,att = 0,def = 0,hit = 0,dodge = 0,crit = 
           0,ten = 0,wreck = 0,resist = 0,special_attr = [],resum = 
           [],striking_distance = 0,tracing_distance = 0,warning_range = 
           0,hate_range = 0,speed = 0,skill = [{1110000003,1}],retime = 
           0,att_time = 0,att_type = 0,drop = 0,exp = 100,out = 
           0,collect_time = 0,collect_count = 0,is_fight_back = 
           0,is_be_atted = 1,is_be_clicked = 1,is_armor = 0,del_hp_each_time 
           = [10,10],figure_visible = 1,is_hide_hp = 0,is_hit_ac = 
           0,exp_share_type = 0,anger = 0};
...
get(10000) ->
    ...
....

图片为观察者结果:enter image description here

【问题讨论】:

标签: memory erlang


【解决方案1】:

听起来您的进程正在为 test_data 模块保存对常量池中对象的引用。这几乎不需要内存,因为引用基本上只是指针。当旧版本的模块被清除时,常量池也随之消失,所以测试服务器不能再仅仅持有一个引用;它需要在自己的堆中有一份数据副本。

查看此讨论on the mailing list

所有文字都属于已加载的模块实例。当那个(旧)模块 实例被清除,所有进程堆都被扫描并且堆包含 这些文字将进行特殊的垃圾收集,其中文字 被复制了。

【讨论】:

  • 谢谢,我明白了。但是如果我有 1000 个这样的进程,当模块实例被清除时,内存就像“泄漏”一样。如果我不触发major gc,内存不会改变。为什么进程文字不会自动生成 gc?有什么好办法让它解决吗?
  • 一般在需要内存的时候处理GC。如果您的进程不经常分配内存,那么它们也不会经常 GC。作为一种解决方案,您可以直接在进程中触发 GC(在计时器上,或在收到消息时等),或使用 gen_server 的休眠功能。
猜你喜欢
  • 2013-01-23
  • 2017-10-01
  • 2018-07-22
  • 2012-02-14
  • 2018-05-19
  • 2020-05-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-11
相关资源
最近更新 更多