我会想,如果我所做的只是 1) 加载一个 NIF 库,2) 执行我的 new/0 方法,3) 通过 F() 释放一切,然后 4) erlang:garbage:collect()我会回到内存的起点。事实上,我正在泄漏内存。显然,我的代码最有可能受到怀疑。
谁能告诉我我做错了什么?
我有以下结构:
typedef struct Node
{
int Key;
ERL_NIF_TERM TermPtr;
struct Node *Next;
} Node;
我的on-load打开资源
int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
ErlNifResourceFlags flags = (ErlNifResourceFlags)(ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER);
NODE_RESOURCE = enif_open_resource_type(env, "linkedlist_nif",
"node_resource",
&node_dtor,
flags,
0);
}
new/0 被映射到这个 NIF:
static ERL_NIF_TERM new_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM term;
Node *Head = (Node *)enif_alloc_resource(NODE_RESOURCE,sizeof(Node));
Head->Next = 0;
term = enif_make_resource(env, Head);
enif_release_resource(Head);
return enif_make_tuple2(env, enif_make_atom_len(env, "ok", 2), term);
}
资源的析构或运算如下:
static void node_dtor(ErlNifEnv* env, void* arg)
{
Node* handle = (Node*)arg;
enif_release_resource(handle);
handle = NULL;
}
最佳答案
因此在 shell 中,您使用 A = your_nif:new() 创建一个值。
然后您使用 f() 释放该值。
然后您 erlang :garbage_collect()。
并且您希望您的内存使用量与开始之前相同(大概)?
这可能不会发生,因为 shell 保留了先前执行结果的历史记录。这将在整个 f().
和 garbage_collect().
中保持对术语的引用,因此您不会看到您期望的内存行为。
你可以这样做:
Before = erlang:memory().
Pid = spawn( fun () ->
A = your_nif:new(),
receive
cleanup -> ok
end
end).
timer:sleep(timer:seconds(1)). % Wait for pid to spawn and allocate term.
During = erlang:memory().
Pid ! cleanup.
After = erlang:memory().
lists:zipwith3(fun ({K, B}, {K, D}, {K, A}) ->
{K, _Values = {B, D, A}, {_Leaked = A - B, _Used = D - B}} end,
Before, During, After).
这应该向您显示测试期间使用的内存的一些近似值(严格来说并不准确,但如果 your_nif:new()
项足够大,它将超过其他内存分配),并且泄漏之后。
关于erlang - 使用 NIF 时如何正确进行垃圾收集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9082542/