LINUX.ORG.RU

Есть ли здесь утечка памяти и если нет, как назвать проблему?

 


0

1

const int arena_el_sz = sizeof(void**);
int arena_size = arena_el_sz;
void** arena = (void**)malloc(arena_size);


void* my_malloc(int size_mem)
{   void* save = malloc(size_mem);
    arena[arena_size/arena_el_sz - 1] = save;
    arena_size += arena_el_sz;
    arena = (void**)realloc(arena, arena_size);
    return save;
}

void do_nothing(void* x){}

#define malloc my_malloc
#define free do_nothing
...

int main()
{
    while(!quit) //очень долго исполняющийся код
    { ...
    }
    #undef free
 
    for(int i = 0; i<arena_size; i++)
    {
       free(arena[i]);
    }
    free(arena);
}

Аналогичный дефайн макроса для calloc и другие очевидные фиксы не приведены в целях сокращения листинга.

★★★★★

Последнее исправление: next_time (всего исправлений: 2)

Если не обращать внимания на то, что, судя по вызову realloc, sizeof(void *) == 1, а последний элемент arena всегда мусор, вся выделенная память будет освобождена перед завершением main. Считать ли это утечкой - решай сам.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

не обращать внимания: возможно, часть арены даже как-то используется в коде, но бОльшая часть лежит мёртвым грузом

next_time ★★★★★
() автор топика
Ответ на: комментарий от vertexua

спасибо, теперь, вроде пофиксил

next_time ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

Считать ли это утечкой - решай сам.

Вопрос, очевидно, в корректности терминологии. Если считать, что в данном коде - утечка, то тогда можно смело утверждать, что сборщики мусора в яве и др. языках, где они есть, не способны справиться с проблемой утечки памяти на 100%. Потому, что в них возможна таже проблема (по существу), что и в этом коде. Более того, в определённых ситуациях, из-за особенностей реализации сборки мусора, эта проблема значительно более вероятна, чем в С/С++.

next_time ★★★★★
() автор топика

я прочитал этот код и теперь меня тошнит, пишу наугад с унитаза

anonymous
()
Ответ на: комментарий от next_time

Потому, что в них возможна таже проблема (по существу)

Какая «та же»? У тебя память гарантированно не освобождается, что бы не происходило в программе. Ни один язык со сборкой мусора не дает такой гарантии.

tailgunner ★★★★★
()

кхм... наверное, начать нужно с того, что размер указателя равен 1 разве что в 8-битных процессорах. во-вторых, если ты хочешь написать пул, то лучше резервировать место блоками, а не реаллоцировать его при каждом чихе, чтобы не мучить себя и систему.
P.S. вижу, что код правится быстрее, чем я пишу посты.

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 3)
Ответ на: комментарий от i-rinat

Конкретно в этом примере используется намерянно неправильно применённый паттерн Арена: https://developers.google.com/protocol-buffers/docs/reference/arenas В С/С++ лучше примера, наверное, не придумать.

А вот в языках со сборкой мусора возможна другая ситуация: статический объект ссылается на пачку других объектов, те на другие, те ещё на какие-то. И так, по цепочке, к половине программы можно получить доступ через статический объект, и, т.о., сборщик мусора не срабатывает.

Но на кеш такая структура данных уже не похожа.

next_time ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

У тебя память гарантированно не освобождается, что бы не происходило в программе.

Да щаз. Никто не запрещает далее работать с памятью через тот же объект arena. Можно даже недомусоросборщик запилить.

next_time ★★★★★
() автор топика
Ответ на: комментарий от next_time

У тебя память гарантированно не освобождается, что бы не происходило в программе.

Да щаз

void do_nothing(void* x){}

#define malloc my_malloc
#define free do_nothing

Можно даже недомусоросборщик запилить.

Я обсуждаю приведенную программу, а не твои фантазии о ней.

tailgunner ★★★★★
()
Ответ на: комментарий от Iron_Bug

если ты хочешь написать пул, то лучше резервировать место блоками, а не реаллоцировать его при каждом чихе, чтобы не мучить себя и систему

очевидно. но: "...и другие очевидные фиксы не приведены в целях сокращения листинга". код приведён просто для примера, мне интересно разобраться с терминологией (см. сообщ. выше).

next_time ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

и что? #define realloc

здесь нет. никто не запрещает написать realloc(x, 0)...

никто не запрещает доступ к переменной arena. никто не запрещает #undef free .. #define free do_nothing.

в примере не рассписано очень много очевидных вещей, иначе он на 2 страницы вышел бы

next_time ★★★★★
() автор топика
Последнее исправление: next_time (всего исправлений: 1)
Ответ на: комментарий от tailgunner

алсо, обсуждая даже ровно в том виде, в каком есть: в абстрактном языке со сборщиком мусора можно прописать:

static Object[] arena;

auto my_malloc(auto x)
{ 
  arena.add(x); 
  return x;
}

#def new(X) my_malloc(new (X)) 

всё, привет. получили туже проблему. всего-то нужна развитая система макросов и, опционально, вывод типов. можно и другими языкозависимыми средствами такое замутить.

next_time ★★★★★
() автор топика
Последнее исправление: next_time (всего исправлений: 1)
Ответ на: комментарий от next_time

никто не запрещает доступ к переменной arena. никто не запрещает #undef free .. #define free do_nothing.

Понятно. Ну что ж, урок мне - не играй с шулером.

tailgunner ★★★★★
()
Ответ на: комментарий от next_time

я одного не пойму: зачем тебе эти дефайны для free? ну не освобождай явно память, если не хочешь. игра с дефайнами оправдана только тогда, когда по-другому ну вообще никак. а тут целиком твой код и ты сам себе режиссёр, как я понимаю.
или, если твой код будет GNU-совместимым, то почему бы просто не перегрузить функции, используя динамическую линковку стандартных вызовов. что-то вроде

void *malloc(size_t size)
{
    void *(*libc_malloc)(size_t) = dlsym(RTLD_NEXT, "malloc");
    void *ptr = libc_malloc(size); 
    return ptr;
}
ессна, код надо оптимизировать, чтобы не дёргать линки каждый раз. но идея, я думаю, понятна.

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 3)

Здесь нет утечки, потому что вся память доступна через семантику arena (помимо живых указателей в стеке), т.е. даже без байтоепства и ручного лазания по адресному пространству. Проблема может называться «слишком отложенное освобождение, ведущее к ENOMEM/OOM», и если это проблема, то создавай дополнительные пулы в более узких циклах. Правда придется либо явно указывать арену и следить чтобы указатели из нее деру не дали, либо мутить какого-то рода рефкаунты, либо еще что.

arturpub ★★
()
Ответ на: комментарий от arturpub

слишком отложенное освобождение, ведущее к ENOMEM/OOM

о, вот это, похоже, годное определение, спасибо, вопрос решён

и если это проблема, то создавай дополнительные пулы в более узких циклах.

не, я тему создавал исключительно ради пополнения словарного запаса

Iron_Bug, vertexua, i-rinat, tailgunner всем спасибо

next_time ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.