如何避免释放存储在具有相同引用计数的容器中的对象
How to avoid freeing objects that are stored in containers with the same reference count
我一直在研究用 c 编写的自定义编程语言的一些功能。目前我正在开发一个系统,该系统对语言中的对象进行引用计数,在 c 中表示为结构,其中包括引用计数。
还有一个功能可以释放所有当前分配的对象(比如在程序退出之前清理所有内存)。现在问题就在这里。
我一直在考虑如何做到最好,但我 运行 遇到了一些问题。让我大致描述一下情况:
分配了 2 个新整数。两者的引用计数均为 1
分配了 1 个新列表,引用计数也为 1
现在两个整数都在列表中,这使它们的引用计数为 2
在这些操作之后,由于某种原因,两个整数都超出了范围,因此它们的引用计数下降到 1,因为它们仍在列表中。
现在我已经完成了这些对象的处理,所以我 运行 删除所有跟踪对象的功能。但是,您可能已经注意到列表和列表中的对象具有相同的引用计数 (1)。这意味着无法决定首先释放哪个对象。
如果我释放列表之前的整数,列表将尝试减少之前释放的整数的引用计数,这将导致段错误。
如果列表在整数之前被释放,它会将整数的引用计数递减为 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% 的时间,列表在整数被释放之前被释放。
释放所有现有对象的更聪明的方法是什么,以便存储在容器中的对象不会在它们所在的容器之前被释放?
这取决于您的意图:
There also is a feature which can free all currently allocated objects (say before the exit of the program to clean up all memory).
如果目标是强制释放每个对象而不考虑其引用计数,那么我将有一个单独的代码块来遍历对象图并释放每个对象而不触及其引用计数。引用计数本身也将最终被释放,因此更新它没有什么意义。
如果目标只是告诉系统 "We don't need the objects anymore" 那么另一种选择是简单地遍历根并减少它们的引用计数。如果没有对它们的其他引用,它们将归零。然后他们将在被释放之前减少他们引用的所有内容的引用计数。这反过来又渗透到对象图中。如果根是唯一保持引用的东西,那么它会有效地释放所有东西。
在 somelist
的引用计数为零之前,您不应释放任何内容。
我一直在研究用 c 编写的自定义编程语言的一些功能。目前我正在开发一个系统,该系统对语言中的对象进行引用计数,在 c 中表示为结构,其中包括引用计数。
还有一个功能可以释放所有当前分配的对象(比如在程序退出之前清理所有内存)。现在问题就在这里。
我一直在考虑如何做到最好,但我 运行 遇到了一些问题。让我大致描述一下情况:
分配了 2 个新整数。两者的引用计数均为 1
分配了 1 个新列表,引用计数也为 1
现在两个整数都在列表中,这使它们的引用计数为 2
在这些操作之后,由于某种原因,两个整数都超出了范围,因此它们的引用计数下降到 1,因为它们仍在列表中。
现在我已经完成了这些对象的处理,所以我 运行 删除所有跟踪对象的功能。但是,您可能已经注意到列表和列表中的对象具有相同的引用计数 (1)。这意味着无法决定首先释放哪个对象。
如果我释放列表之前的整数,列表将尝试减少之前释放的整数的引用计数,这将导致段错误。
如果列表在整数之前被释放,它会将整数的引用计数递减为 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% 的时间,列表在整数被释放之前被释放。
释放所有现有对象的更聪明的方法是什么,以便存储在容器中的对象不会在它们所在的容器之前被释放?
这取决于您的意图:
There also is a feature which can free all currently allocated objects (say before the exit of the program to clean up all memory).
如果目标是强制释放每个对象而不考虑其引用计数,那么我将有一个单独的代码块来遍历对象图并释放每个对象而不触及其引用计数。引用计数本身也将最终被释放,因此更新它没有什么意义。
如果目标只是告诉系统 "We don't need the objects anymore" 那么另一种选择是简单地遍历根并减少它们的引用计数。如果没有对它们的其他引用,它们将归零。然后他们将在被释放之前减少他们引用的所有内容的引用计数。这反过来又渗透到对象图中。如果根是唯一保持引用的东西,那么它会有效地释放所有东西。
在 somelist
的引用计数为零之前,您不应释放任何内容。