1
Я написал Erlang C NIF, который возвращает указатель на структуру после вызова new и на данный момент просто увеличивает при вставке переменную. Мне интересно, как правильно уничтожить исходный ресурс или по крайней мере отметить его для GC. Мне не повезло.Правильно освободить память alloced с enif_resource_alloc
#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)
Я не понимаю, когда или кто держит последний ресурс. Я уже использую enif_release_resource (q); перед возвратом из новой функции. Что еще я должен делать? – BAR
@ user417896: Если вы вернули ресурс с enif_make_resource, то абсолютно ничего. Эрланг использует подсчет ссылок на терминах, чтобы определить, когда больше нет экземпляров термина, плавающего вокруг. Когда это так, автоматически собираются мусор и вызывается ваш деструктор. –
Это относится только к терминам, возвращенным с помощью enif_make_resource; вполне возможно выделить объект ресурса и явно освободить его с помощью enif_release_resource, но после вызова enif_make_resource он управляется памятью. Вы также можете явно опубликовать его, если только один процесс имеет ссылку на этот термин, и этот процесс вызывает nif, который вызывает enif_release_resource. Достаточно сказать, что enif_release_resource уменьшает опорный счетчик, тогда как enif_make_resource увеличивает его. –