PHP:Linkedlist节点对象垃圾回收问题


PHP: Linkedlist node objects garbage collection issue

将第一个和最后一个节点对象标识符设置为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...........................
.............................................................

干杯。