Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Сборщик мусора. Удаляется объект, который в дисплей листе. (http://www.flasher.ru/forum/showthread.php?t=192575)

Волгоградец 16.01.2013 12:26

Сборщик мусора. Удаляется объект, который в дисплей листе.
 
Привет. Заголовок немного желтоват. На самом деле код выглядит так:

Код AS3:

package {
 
        import flash.display.Sprite;
        import flash.events.MouseEvent;
 
        public class GCTest extends Sprite {
 
                public function GCTest() {
                        stage.addEventListener(MouseEvent.CLICK, stageMouseClickHandler);
                }
 
                private function stageMouseClickHandler(event:MouseEvent):void {
                        var a:A = new A();
                        addChild(a.vis);
                }
        }
}
 
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.system.System;
 
internal class A {
 
        public var vis:Sprite = new Sprite();
 
        private const _SHAPE:Shape = new Shape();
 
        function A() {
                vis.graphics.beginFill(0xFF0000);
                vis.graphics.drawCircle(0, 0, 50);
                vis.graphics.endFill();
 
                _SHAPE.addEventListener(Event.ENTER_FRAME, entarFrameHandler);
        }
 
        private function entarFrameHandler(event:Event):void {
                trace('enter frame handler');
                System.gc();
        }
}

При клике по сцене создается объект... и тут же удаляется сборщиком мусора. Насколько я знаю принцип работы ГЦ, объект не уничтожается, если есть хотя бы одна ссылка на него. Что мы имеем тут? _SHAPE находится не в дисплей листе, но является полем класса A. vis также является полем класса A. Сам класс A наследник Object и объект этого класса создается в локальной области видимости, на него ссылок нет, т.е. он явный кандидат на уничтожение. НО! vis, который является дисплей обжектом и полем класса A находится в дисплей листе. Собственно вопрос - какой именно из этих объектов уничтожается и почему?

toFL 16.01.2013 12:32

Ну так все правильно. После вот этого:
Код AS3:

var a:A = new A();
addChild(a.vis);

"a.vis" будет живет долго и счастливо, так как он в дисплей листе. А вот "a" умирает, так как на него нет ни одной ссылки. GC удаляет не целостные объекты и не подмножества...а те на которые нет ссылок.

Волгоградец 16.01.2013 12:47

Но если он его удалит, значит он должен удалить все его поля, в том числе и vis. Т.е. память, занимаемая объектами должна освободиться. Но vis на месте и я могу обращаться к нему. А что если позже что-то перезапишется на эту память?

Wolsh 16.01.2013 12:53

Не путайте ссылку и значение. Ссылка будет удалена, а объект останется, так как на него есть другая ссылка — в контейнере.

Добавлено через 7 минут
Код AS3:

public var vis:Sprite = new Sprite();

public var vis:Sprite — это переменная, хранящая ссылку. Это не сам спрайт. Это ссылка, где его искать.
new Sprite(); — вот собственно "сам" спрайт, создаваемый где-то в памяти. Где — сохраняется в переменной. Или не сохраняется явно, а только во внутреннем хэше контейнера:
Код AS3:

addChild(new Sprite());


Волгоградец 16.01.2013 13:03

Wolsh, не понял. Если срабатывает ГЦ, то он именно удаляет объекты. Вот еще пример.

Код AS3:

package {
 
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.events.MouseEvent;
        import flash.system.System;
 
        public class GCTest extends Sprite {
 
                public function GCTest() {
                        stage.addEventListener(MouseEvent.CLICK, stageMouseClickHandler);
                }
 
                private function stageMouseClickHandler(event:MouseEvent):void {
                        var a:A = new A();
                        addChild(a.s);
 
                        var s:Sprite = new Sprite();
                        addChild(s);
                        s.addEventListener(Event.ENTER_FRAME, test, false, 0, true);
                }
 
                private function test(event:Event):void {
                        trace('inside main');
                        System.gc();
                }
        }
}
 
import flash.display.Sprite;
import flash.events.Event;
import flash.system.System;
 
internal class A {
 
        public var s:Sprite = new Sprite();
 
        function A() {
                s.addEventListener(Event.ENTER_FRAME, enterFrameHandler, false, 0, true);
                s.graphics.beginFill(0x00FF00);
                s.graphics.drawCircle(0, 0, 50);
                s.graphics.endFill();
        }
 
        private function enterFrameHandler(event:Event):void {
                trace('inside A');
                System.gc();
        }
}

Тут еще интересней. s, что внутри A удалится сразу же, хотя он в дисплей листе. s, что внутри Main будет работать бесконечно долго. В чем разница между ними?

expl 16.01.2013 13:28

Цитата:

Сообщение от Волгоградец (Сообщение 1115912)
Wolsh, не понял. Если срабатывает ГЦ, то он именно удаляет объекты.

Примерно можно использовать такую модель:
Объект - это кусок памяти, в котором лежат:
- вспомогательная информация
- ссылки на другие объекты (физически 4 байта)
- примитивные типы (int, Number) - физически 4, 8 байт
И вот это всё лежит в линеечку (для одного объекта)

Ссылки ссылаются на другие объекты. Т.е. удалить объект - это удалить как раз ссылки на другие и примитивные значения.

Объекты и их ссылки представляют собой не _дерево_, а _граф_
Здесь нельзя просто взять и удалить вместе с объектом те, на которые он ссылается. На эти ссылочные объекты может ссылаться кто-то ещё.

По поводу примера кода - не смотрел ещё, вообще странно.

Волгоградец 16.01.2013 13:35

Цитата:

Здесь нельзя просто взять и удалить вместе с объектом те, на которые он ссылается. На эти ссылочные объекты может ссылаться кто-то ещё.
Вот здесь немного проясняется. Я думал, что ГЦ просто не может убить объект, внутри которого есть "живые" объекты. Оказывается может.

Пример, да, странный. У меня еще парочка необъяснимых имеется.

iflamberg 16.01.2013 14:40

Пример не странный, пример реальный. Я впервые столкнулся с таким удалением, когда делал игрушку, которая пачкой loader'ов загружала множество кусочков карты по 100 на 100 пикселей. Так вот я просто создавал в теле функции loader'ы и сразу кидал на сцену, нигде не хранил. И на некоторых компьютерах я увидел, что объекты лоадера ГЦ съедает даже еще до того, как картинка загрузилась. Причем, не очень уже хорошо помню, давно это было, но уверен, что на все загрузчики были навешаны слушатели, и не weak, и все равно ГЦ их съедал. Решил проблему хранением массива этих загрузчиков в классе, пока они все не загрузились.

expl 16.01.2013 16:00

Цитата:

на все загрузчики были навешаны слушатели, и не weak, и все равно ГЦ их съедал.
Всё правильно, он не сьёдал бы их, только если бы слушатель принадлежал самому лоадеру и Вы бы повесили его слушатель на объект, который не подлежал бы сборке мусора.

А так вы навесили слушатель - т.е. добавили ссылку на себя в лоадер - как это должно помешать его сборке?

По порядку:
Код AS3:

private function stageMouseClickHandler(event:MouseEvent):void {
                        var a:A = new A();
                        addChild(a.vis);
}

1. Вы создали экземпляр A
2. Вы взяли у экземпляра A vis и добавили его в список отображения
3. Вы нигде не сохранили ссылку на сам экземпляр A (функция отработала - ссылок на экземпляр A не осталось, остался только vis в списке отображения)
Что должно получиться:
- ничего не мешает собрать GC экземпляр A
- GC не может собрать vis.
Код AS3:

public var vis:Sprite = new Sprite();
 
        private const _SHAPE:Shape = new Shape();
 
        function A() {
                vis.graphics.beginFill(0xFF0000);
                vis.graphics.drawRect(-25, -25, 50, 50);
                vis.graphics.endFill();
 
                _SHAPE.addEventListener(Event.ENTER_FRAME, entarFrameHandler);
        }

3. Вы вешаете слушатель не на vis, а на _SHAPE
4. _SHAPE на сцену не добавляется
5. на _SHAPE ссылается экземпляр A, на который вы не сохранили никаких ссылок
Что должно произойти:
- Экземпляр _SHAPE должен быть снесён сборщиком мусора

Вывод: Хороший пример, демонстрирующи работу GC и никакой мистики!

iflamberg 16.01.2013 16:18

Да, хороший пример, в мемориз однозначно.


Часовой пояс GMT +4, время: 15:08.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.