Как избежать освобождения объектов, которые хранятся в контейнерах с одинаковым количеством ссылок - PullRequest
2 голосов
/ 05 апреля 2019

Я работал над некоторыми функциями пользовательского языка программирования, написанного на c.В настоящее время я работаю над системой, которая выполняет подсчет ссылок для объектов на языке, которые в c представлены как структуры, среди прочего, со счетчиком ссылок.
Также есть функция, которая может освободить все выделенные в данный момент объекты (скажем перед выходом программы очистить всю память).Теперь в этом и заключается проблема.

Я думал о том, как сделать это лучше, но у меня возникают некоторые проблемы.Позвольте мне набросать ситуацию немного:

2 новых целых числа выделены.оба имеют счетчик ссылок 1
1 новый список назначен, также с счетчиком ссылок 1

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

Теперь я закончил с этими объектами, поэтому я запустил функцию, чтобы удалить все отслеживаемые объекты.Однако, как вы могли заметить, список и объекты в списке имеют одинаковый счетчик ссылок (1).Это означает, что нет способа решить, какой объект освободить первым.

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

Если список будет освобожден раньшецелые числа, это уменьшило бы число ссылок целых чисел до 0, что также автоматически освобождает их, и не нужно предпринимать никаких дальнейших шагов для освобождения целых чисел.Они больше не отслеживаются.

В настоящее время у меня есть система, которая работает большую часть времени, но не для примера, который я привел выше, где я освобождаю объекты на основе их счетчика ссылок.Самое высокое количество последних.Это, очевидно, работает только до тех пор, пока целые числа имеют большее число ссылок, чем список, что видно из приведенного выше примера, не всегда так.(Это работает только при условии, что целые числа не выпали из области видимости, поэтому у них все еще более высокое число ссылок, чем в списке)

Примечание: я уже нашел один способ, который мне действительно не нравится: добавлениефлаг для каждого объекта, указывающий, что он находится в контейнере, поэтому не может быть освобожден.Мне не нравится это, потому что это добавляет некоторые накладные расходы памяти для каждого выделенного объекта, и когда есть циклическая зависимость, ни один объект не будет освобожден.Конечно, детектор циклов мог бы это исправить, но желательно, чтобы я делал это только с подсчетом ссылок.

Позвольте мне привести конкретный пример описанных выше шагов:


//this initializes and sets a garbage collector object. 
//Basically it's a datastructure which records every allocated object,
//and is able to free them all or in the future 
//run some cycle detection on all objects. 
//It has to be set before allocating objects 

garbagecollector *gc = init_garbagecollector();
set_garbagecollector(gc);

//initialize a tracked object fromthe c integer value 10
myobject * a = myinteger_from_cint(10); 
myobject * b = myinteger_from_cint(10);

myobject * somelist = mylist_init();
mylist_append(somelist,a);
mylist_append(somelist,b);

// Simulate the going out of scope of the integers.
// There are no functions yet so i can't actually do it but this
// is a situation which can happen and has happened a couple of times
DECREF(a);
DECREF(b);

//now the program is done. all objects have a refcount of 1

//delete the garbagecollector and with that all tracked objects
//there is no way to prevent the integers being freed before the list
delete_garbagecollector(gc);

что, конечно, должно произойти, это то, что в 100% случаев список освобождается раньше, чем целые числа.

Что может быть более разумным способом освобождения всех существующих объектов таким образом, чтобы объекты, хранящиеся в контейнерах, неосвобожден до того, как контейнеры будут в них?

Ответы [ 2 ]

1 голос
/ 05 апреля 2019

Это зависит от вашего намерения:

Также имеется функция, которая может освободить все выделенные в данный момент объекты (скажем, до выхода из программы, чтобы очистить всю память).

Если цель состоит в том, чтобы принудительно освободить каждый отдельный объект независимо от его количества ссылок, то у меня был бы отдельный кусок кода, который просматривает граф объектов и освобождает каждый объект, не касаясь его счетчика ссылок. Сам счетчик тоже будет освобожден, так что нет смысла его обновлять.

Если цель состоит в том, чтобы просто сказать системе: «Нам больше не нужны объекты», то другой вариант - просто пройтись по корням и уменьшить их количество ссылок. Если нет других ссылок на них, они достигнут нуля. Затем они уменьшат количество ссылок на все, на что они ссылаются, перед тем как их освободят. Это в свою очередь просачивается через граф объектов. Если корни - единственное, что удерживает ссылки в точке, которую вы называете, это эффективно освободит все.

0 голосов
/ 06 апреля 2019

Вы не должны ничего освобождать, пока счетчик ссылок для somelist не станет равным нулю.

...