将第一个和最后一个节点对象标识符设置为NULL将导致链表内所有节点对象的即时自动垃圾收集,因为没有引用包括第一个和第二个节点在内的所有节点对象。
$this->first = NULL
$this->last = NULL
我们是否需要对完整的链表进行迭代,并逐个取消设置每个节点对象标识符?
我认为,将first和last设置为NULL就足够了,PHP代表我们在后台进行垃圾收集。
如果我错了,请纠正我。
如果您正在运行PHP<5.3.0并且您使用的是双链接列表,则不会释放任何节点。这是因为早期的PHP版本只使用引用计数[1],无法识别循环引用。即使在单链表中,也可能需要通过垃圾收集器的"n"次才能释放整个列表,这取决于所使用的确切算法(尽管我认为这不太可能)。
为了进一步解释,在双链表中,每个节点都指向它之前和之后的节点。考虑有序的节点a、B、C。这意味着a由指向,B、C由B指向,B由a和C指向。因此,除非您自己明确取消设置节点,否则它们的引用计数将始终为非零。
对于单链表,以及相同的节点A、B、C,每个节点都被前一个节点指向,但A除外,它没有被其他节点指向。因此,如果删除对A的引用,它将被垃圾回收。然后,由于不再指向B,它将被释放,依此类推。但是,假设垃圾收集器以相反或随机的顺序(而不是从左到右的最佳顺序)访问列表。然后,它可以先看B,得出结论A仍然指向它,因此不需要释放。然后GC释放A并完成。尽管如此,GC算法更有可能持续收集引用计数为零的内存,直到没有更多可收集的内存为止,这将避免这个问题。
值得庆幸的是,从PHP 5.3.0开始,我们不必担心循环引用[2]。该算法通过从根内存节点构建树来工作。任何未包含在最终树中的内容都必须是孤立的(因此,由于循环引用,只能保持活动状态),因此可以释放。因此,是的,只要程序中没有任何其他节点指向列表中的任何节点,那么通过删除对开始和结束的引用,整个列表就会被释放。
注意,释放孤立循环引用的算法比简单的引用计数更昂贵。显式释放代码可能是有益的,也可能不是有益的。必须进行仔细的基准测试才能发现这一点。
-
[1]http://www.php.net/manual/en/features.gc.refcounting-basics.php
-
[2]http://www.php.net/manual/en/features.gc.collecting-cycles.php
有时我会遇到PHP垃圾收集过程的问题。
你可以在链表的实现中为这些东西做一个变通。
-
每次创建数据结构时,都要将其创建为函数中的局部变量,不是全球性的。稍后,在代码的其他部分分配,您将在哪里使用它。如果您直接分配一个变量,您可能会有一个副本到相同的引用,而不是具有相同数据的新结构。
-
我建议将"列表"结构作为一个独立的结构来实现,不仅仅是指向第一个或最后一个节点的指针。
-
在链表的情况下,我添加了两个特殊的节点,它们的工作方式类似于您的"第一个"&"最后",它不存储任何数据,并且永远不会被删除,除非整个链表,将被删除。当列表为空时,它们相互链接,当添加真实的数据节点时,它们被设置在这些节点之间。
-
删除第一个节点时,不会删除特殊的"第一个"节点标记,而是在特殊的"第一个"标记之后的节点。
-
删除最后一个节点时,不会删除特殊的"最后一个"节点标记,而是位于特殊"最后"标记之前的节点。
建议:
<?php
/* listitem */ function newitem($data)
{
// executing a function that returns
// a local variable,
// forces php to create a new item, each time,
// instead of making a copy,
// that conflicts with garbage collection
/* listitem var */ $Result = array(
"data" => $data,
"prev" => null,
"next" => null,
);
return $Result;
} // listitem function newitem(...)
/* linkedlist */ function newlist()
{
// executing a function that returns
// a local variable,
// forces php to create a new item, each time,
// instead of making a copy,
// that conflicts with garbage collection
/* linkedlist var */ $Result = array(
"start" => newitem(); // <- "marker" for start of list, don't store data here
"finish" => newitem(); // <- "marker" for end of list, don't store data here
)
return $Result;
} // linkedlist function newlist(...)
/* void */ function linkitem(&$before, &after)
{
if (($before != null) && ($after != null))
{
"start" <=> "item"
$before["next"] = $after;
$after["prev"] = $before;
}
} // void function linkitem(...)
/* void */ function additem(&$list, &item)
{
if ($item != null)
{
"start" <=> "item"
linkitem(/* & */ $list["start"], /* & */ $item);
"item" <=> "finish"
linkitem(/* & */ $item, /* & */ $list["start"]);
}
} // void function additem(...)
/* void */ function example()
{
/* linkedlist var */ $SolarSystem = newlist();
/* listitem var */ $item = null;
$item = newitem("Sun");
// check for reference parameters
additem( /* & */ $SolarSystem, /* & */ $item);
$item = newitem("Mercury");
additem( /* & */ $SolarSystem, /* & */ $item);
$item = newitem("Venus");
additem( /* & */ $SolarSystem, /* & */ $item);
// ...
} // void function example(...)
?>
视觉表示可以是这样的:
.............................................................
....+-------------------+....................................
....| SolarSystem |....................................
....+---------+---------+....................................
..............|..............................................
..............v..............................................
....+---------+---------+...........null.....................
....| Last | First |............^.......................
....+---+-----+----+----+............|.......................
........|..........|.........+-------+-+.....................
........|..........+-------->| prev |.....................
........|....................+---------+....+-----------+....
........|....................| data +--->| "Sun" |....
........|....................+---------+....+-----------+....
........|....................| next |.....................
........|....................+-+-------+.....................
........|......................|.....^.......................
........|......................v.....|.......................
........|....................+-------+-+.....................
........|....................| prev |.....................
........|....................+---------+....+-----------+....
........|....................| data +--->| "Mercury" |....
........|....................+---------+....+-----------+....
........|....................| next |.....................
........|....................+-+-------+.....................
........|......................|.....^.......................
........|......................v.....|.......................
........|....................+-------+-+.....................
........|....................| prev |.....................
........|....................+---------+....+-----------+....
........+------------------->| data |--->| "Venus" |....
.............................+---------+....+-----------+....
.............................| next |.....................
.............................+-+-------+.....................
...............................|.............................
...............................v.............................
..............................null...........................
.............................................................
干杯。