|
|
|
| Имеется класс дерева, что-то типа
class Tree {
protected $RootNode;
}
|
И класс узла, что-то типа
class Node {
protected $Tree;
protected $ParentNode;
protected $ChildNodes = array();
}
|
Предпологается, что текущий узел хранит ссылки на дерево, родительский узел и дочерние узлы, а родительский узел хранит ссылку на текущий узел (в $ChildNodes), дочерние узлы хранят ссылку на текущий узел (в $ParentNode) и дерево хранит ссылку на корневой узел.
Получаются кольцевые ссылки (когда объекты хранят ссылки на друг друга), а сборщик мусора не умеет обрабатывать такие ситуации и объекты остаются в памяти, даже если видимых ссылок в программе на них не осталось.
Подскажите, пожалуйста, решение проблемы удаления объектов дерева и узлов? | |
|
|
|
|
|
|
|
для: St.Devil
(09.10.2009 в 00:54)
| | Где закольцованность-то?
Сначала нужно удалить ссылку на удаляемый элемент из childNodes родителя, а потом рекурсивно удалить childNodes удаляемого элемента и всех его детей. | |
|
|
|
|
|
|
|
для: Саня
(09.10.2009 в 08:49)
| | Например:
public function foo(){
$tree = new Tree();
$child_node = $tree->createNode();
$tree->RootNode->addNode($child_node);
return;
}
|
Ресурсы не освободятся, т.к. узлы будут хранить ссылки друг на друга и на дерево, которое в свою очередь будет хранить ссылку на корневой узел.
Вы предлагаете освобождать ресурсы в ручную (например $tree->clear()) каждый раз, когда необходимо уничтожить дерево?
А что если кто-нибудь из разработчиков (в команде их много) забудет это сделать? Память будет занята до конца работы скрипта, а дерево может быть очень большое. И как потом искать в огромном проекте, где забыли очистить дерево?
Может существует корректный способ освобождения памяти сброщиком мусора? Может нужно как то классы дерева и узла по-другому организовать? | |
|
|
|
|
|
|
|
для: St.Devil
(09.10.2009 в 08:59)
| | Деструкторы для кого придуманы? | |
|
|
|
|
|
|
|
для: Саня
(09.10.2009 в 09:07)
| | Автоматически деструктор вызывается с помощью сборщика мусора, который его не вызовет, пока на объект есть хотя бы одна ссылка.
Попробуйте выполнить у себя код:
class Tree {
protected $RootNode;
public function __construct(){
$this->RootNode = new Node($this);
}
public function __destruct(){
echo '<div>Tree destruct</div>';
}
}
class Node {
protected $Tree;
public function __construct(Tree $tree){
$this->Tree = $tree;
}
public function __destruct(){
echo '<div>Node destruct</div>';
}
}
$tree = new Tree();
unset($tree);
echo '<div>Script finish</div>';
|
Результатом будет:
Script finish
Tree destruct
Node destruct
|
Т.е. деструкторы Tree и Node вызовутся уже после завершения работы скрипта, хотя единственная видимая ссылка на дерево была удалена до вывода сообщения о завершении работы скрипта | |
|
|
|
|
|
|
|
для: St.Devil
(09.10.2009 в 09:15)
| | У вас скрипт висит вечно? Скрипт отработает и сборщик подчистит весь мусор. | |
|
|
|
|
|
|
|
для: GeorgeIV
(09.10.2009 в 10:01)
| | А если деревьев несколько? Зачем хранить в памяти деревья (особенно если они огромные), с которыми уже не нужно будет работать? | |
|
|
|
|
|
|
|
для: St.Devil
(09.10.2009 в 09:15)
| | Обязательно связывать Tree с нодами? Нельзя ноду сделать булевое поле "isRoot", указывающее на то, что он корневой? И вместо protected $Tree; сделать protected $RootElement; | |
|
|
|