【问题标题】:Properly free memory alloc'd with enif_resource_alloc使用 enif_resource_alloc 正确释放内存分配
【发布时间】:2013-01-28 02:31:16
【问题描述】:

我写了一个 Erlang C NIF,它在调用 new 后返回一个指向结构的指针,现在只在插入时增加一个变量。我想知道如何正确销毁原始资源,或者至少将其标记为 GC。我运气不好。

#include <stdio.h> 
#include "erl_nif.h"


typedef struct level {
    float a;
    float b;
} LVL;

// data array with key being the price
typedef struct book {
    int array_size; // # of TTL indices
    int len; // # of Occupied indices (inc. val) from bestPriceIndex
    int max_len; 

    LVL lvl_data[];

} Book;


static ErlNifResourceType *MEM_RESOURCE;


    static int
on_load(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM load_info)
{
    ErlNifResourceFlags flags = (ErlNifResourceFlags)(ERL_NIF_RT_CREATE);

    if ( (MEM_RESOURCE = enif_open_resource_type(env, 
            NULL,
            "mem_resource", 
            NULL, //dtor
            flags, 
            NULL)) == NULL)
        return -1;

    return 0;
}


    static ERL_NIF_TERM 
new( ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] ) 
{   
    int max_len = 50;

    int mem_size = sizeof(Book) + max_len * sizeof(LVL);
    Book *q = enif_alloc_resource(MEM_RESOURCE, mem_size );
        if( q == NULL ) return enif_make_string(env, "could not alloc", ERL_NIF_LATIN1);

    q->lvl_data[0].a = 7.0;     

    ERL_NIF_TERM term = enif_make_resource(env, q);

    enif_release_resource(q);

    return term;
};


    static ERL_NIF_TERM 
insert( ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] ) 
{
    Book *p;
    if (!enif_get_resource(env, argv[0], MEM_RESOURCE, (void **)&p)) 
       return enif_make_badarg(env); 

    float x = ++p->lvl_data[0].a;

    return enif_make_string(env, "okk", ERL_NIF_LATIN1);
};


static ErlNifFunc nif_funcs[] = 
{ 
    {"new", 0, new},
    {"insert", 1, insert}
};

ERL_NIF_INIT( test, nif_funcs, on_load, NULL, NULL, NULL )

【问题讨论】:

    标签: c erlang alloc


    【解决方案1】:

    当没有terms持有该资源时,GC会自动收集该资源。

    【讨论】:

    • 我不明白何时或谁拥有最后一个资源。我已经使用 enif_release_resource(q);就在从新功能返回之前。我还必须做什么?
    • @user417896:如果您使用 enif_make_resource 返回了资源,那么绝对没有。 Erlang 使用对术语的引用计数来确定何时不再有术语的副本浮动。在这种情况下,它会自动被垃圾收集并调用你的析构函数。
    • 这仅适用于使用 enif_make_resource 返回的术语;完全可以分配资源对象并使用 enif_release_resource 显式释放它,但是一旦调用 enif_make_resource 它是内存管理的。如果只有一个进程引用该术语并且该进程调用调用 enif_release_resource 的 nif,您也可以显式释放它。可以说 enif_release_resource 减少引用计数器,而 enif_make_resource 增加它。
    • @Soup d'Campbells 感谢您提供的信息,但需要澄清的是,紧跟在函数 new 中的 enif_make_resource 之后的 enif_release_resource 是否不正确?
    • 不,事实上它是必要的(它可以延迟,但你最终必须释放它)。在您的代码中: enif_alloc_resource 创建一个引用计数为 1 的内存管理资源。 enif_make_resouce 从资源中生成一个有效的 erlang 项 增加引用计数器,因此之后它的计数为 2。 enif_release_resource 再次递减它,留下term 作为唯一有效的参考。它被分配给调用进程的环境,因此当该进程死亡并被垃圾收集时,最终引用被删除,析构函数被撤销,内存被释放。
    猜你喜欢
    • 2021-04-21
    • 2015-12-17
    • 2012-01-22
    • 2016-03-15
    • 1970-01-01
    • 1970-01-01
    • 2011-12-09
    • 1970-01-01
    • 2011-05-16
    相关资源
    最近更新 更多