В С++ этому в принципе соответствует включение поля по значению. Оно ведет себя как композиция. В результате, деструктор по умолчанию работает правильно и автоматически. Это, собственно, ровно то, что и сделано у нас.
Не вижу, как включение поля по значению в плюсах могло бы решить проблему утечки для listeners. Если мы где-то сохранили ссылку на такое поле - она станет некорректной, когда объект умрёт. И, соответственно, если нам нужно гарантировать, что сохранённая ссылка корректна - придётся удерживать в памяти весь объект (привет, COM с его GetOuterUnknown). Т.е. опять нужна или явная отписка, или weak references.
> Не вижу, как включение поля по значению в плюсах могло бы решить проблему утечки для listeners.
Это позволяет автоматически сгенерировать корректный деструктор. Который пройдется по составному состоянию всех виджетов на странице, и рекурсивно отпишет агрегированные объекты от событий. Для этого системе надо отличать композицию от ассоциаций, чтобы не прибить то, что лежит в синглтоне.
Деструктор состояния в свою очередь вызывается автоматически при вынимании виджета из DOM. То есть, все надежно, и явной отписки нет.
Ну то есть, для данного примера состояние страницы будет выглядеть примерно так:
state : { selectedUsers : User.Collection.Refs }
User.Collection - это конструктор коллекции юзеров. Добавляя к нему Refs - мы получаем коллекцию, которая не пытается брать ownership над своими элементами, и деструктор которой не разрушает объекты внутри нее (но отписывает от событий).
В итоге, когда состояние страницы будет прибито, объекты user внутри синглтона будут живы. Но selectedUsers отпишется от событий, и умрет.
Так. Похоже, я запутался. 1. "Добавляя к нему Refs - мы получаем коллекцию, которая не пытается брать ownership над своими элементами" - а как делать enumerate объектов в коллекции, если weakrefs нету? Или мы ходим по всем объектам DOM и проверяем, не у нас ли он лежит? Но это ж ад... 2. Как достигается отсутствие ссылок от юзеров на коллекцию? Просто запрет ссылок на неё? Или перенаправление этих ссылок на родительский объект?
Или всё вообще сводится к "вот этой коллекцией я точно владею, поэтому на деструкторе выкинем из неё все элементы"? Т.е. суть композиции - один флажок, учитываемый деструктором? (а по сути - создание "дерева владения", в котором деструктор вышестоящего объекта обрывает все связи в дереве, причём деструктор даже не настоящий, а вызывается при удалении из DOM?)
P.S. Капча достала. Почему жж-программеры не могут задетектить, что юзер один и тот же (залогинен же) и раз за разом капчу успешно решает?
У UI-виджетов во многих фреймворках уже есть деструктор, который вызывается при смене раута и вынимании виджета из DOM. В React это componentWillUnmount, например
( ... )
Печально это всё на самом деле. По сути, поверх одной модели владения (ссылки и gc) пришлось накрутить ещё одну, но уже не допускающую циклов. В reference-counting модели (я за последние годы к ней привык - под macos gc не успел даже попробовать, как его задепрекейтили в пользу arc) всё несколько проще, но, конечно, даны другие способы выстрелить себе в ногу (любимый метод создания циклических ссылок - лямбды [blocks]).
Кстати, не в курсе - текущие реализации js используют чистый gc или reference-counting-based оптимизации применяются (т.е. порой объект может быть убит сразу, как кончились ссылки на него, не дожидаясь прохода gc)?
Это все печально неимоверно. Я думал и о счетчике ссылок поверх, который бы включал деструкторы, но решил что не стоит. От явной агрегации много другой пользы - объекты правильно копируются by default, например.
Текущие реализации GC в JS используют mark-and-sweep, V8 использует stop-and-copy. Счетчиков ссылок, насколько мне известно, не использует никто.
В функциональных языках применяется оптимизация известная с LISP машин - однобитные счетчики ссылок. Специально для элементов однонаправленных списков. В JS это не поможет.
Вот это должно как-то работать в IE11. В принципе, на этом можно собрать движок событий - достаточно пропустить все ссылки через WeakMap. И тогда ликов не будет.
Что отличная идея, вопрос только, насколько медленно это будет работать в сравнении с обычными ссылками. Я сделаю экспериментальный движок, посмотрим. Может, будет наоборот быстрее - с ними отписка от событий гораздо проще.
И правильно ли я понимаю, что для composited-полей и будут доступны только слабые ссылки? (ну то есть если выбо
Reply
Reply
Если мы где-то сохранили ссылку на такое поле - она станет некорректной, когда объект умрёт. И, соответственно, если нам нужно гарантировать, что сохранённая ссылка корректна - придётся удерживать в памяти весь объект (привет, COM с его GetOuterUnknown).
Т.е. опять нужна или явная отписка, или weak references.
Reply
Это позволяет автоматически сгенерировать корректный деструктор. Который пройдется по составному состоянию всех виджетов на странице, и рекурсивно отпишет агрегированные объекты от событий. Для этого системе надо отличать композицию от ассоциаций, чтобы не прибить то, что лежит в синглтоне.
Деструктор состояния в свою очередь вызывается автоматически при вынимании виджета из DOM. То есть, все надежно, и явной отписки нет.
Reply
state : {
selectedUsers : User.Collection.Refs
}
User.Collection - это конструктор коллекции юзеров. Добавляя к нему Refs - мы получаем коллекцию, которая не пытается брать ownership над своими элементами, и деструктор которой не разрушает объекты внутри нее (но отписывает от событий).
В итоге, когда состояние страницы будет прибито, объекты user внутри синглтона будут живы. Но selectedUsers отпишется от событий, и умрет.
Reply
1. "Добавляя к нему Refs - мы получаем коллекцию, которая не пытается брать ownership над своими элементами" - а как делать enumerate объектов в коллекции, если weakrefs нету? Или мы ходим по всем объектам DOM и проверяем, не у нас ли он лежит? Но это ж ад...
2. Как достигается отсутствие ссылок от юзеров на коллекцию? Просто запрет ссылок на неё? Или перенаправление этих ссылок на родительский объект?
Или всё вообще сводится к "вот этой коллекцией я точно владею, поэтому на деструкторе выкинем из неё все элементы"? Т.е. суть композиции - один флажок, учитываемый деструктором? (а по сути - создание "дерева владения", в котором деструктор вышестоящего объекта обрывает все связи в дереве, причём деструктор даже не настоящий, а вызывается при удалении из DOM?)
P.S. Капча достала. Почему жж-программеры не могут задетектить, что юзер один и тот же (залогинен же) и раз за разом капчу успешно решает?
Reply
Reply
В reference-counting модели (я за последние годы к ней привык - под macos gc не успел даже попробовать, как его задепрекейтили в пользу arc) всё несколько проще, но, конечно, даны другие способы выстрелить себе в ногу (любимый метод создания циклических ссылок - лямбды [blocks]).
Кстати, не в курсе - текущие реализации js используют чистый gc или reference-counting-based оптимизации применяются (т.е. порой объект может быть убит сразу, как кончились ссылки на него, не дожидаясь прохода gc)?
Reply
Текущие реализации GC в JS используют mark-and-sweep, V8 использует stop-and-copy. Счетчиков ссылок, насколько мне известно, не использует никто.
В функциональных языках применяется оптимизация известная с LISP машин - однобитные счетчики ссылок. Специально для элементов однонаправленных списков. В JS это не поможет.
Reply
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet
Но не работают в IE. Совсем.
Reply
Вот это должно как-то работать в IE11. В принципе, на этом можно собрать движок событий - достаточно пропустить все ссылки через WeakMap. И тогда ликов не будет.
Что отличная идея, вопрос только, насколько медленно это будет работать в сравнении с обычными ссылками. Я сделаю экспериментальный движок, посмотрим. Может, будет наоборот быстрее - с ними отписка от событий гораздо проще.
Ну, и поддержку IE10 мы пока убрать не можем.
Reply
Leave a comment