Leave a comment

aamonster November 5 2016, 10:29:58 UTC
Вроде в увлекательном мире крестиков эта проблема обычно решается через weak references?

И правильно ли я понимаю, что для composited-полей и будут доступны только слабые ссылки? (ну то есть если выбо

Reply

gaperton November 5 2016, 17:45:18 UTC
В С++ этому в принципе соответствует включение поля по значению. Оно ведет себя как композиция. В результате, деструктор по умолчанию работает правильно и автоматически. Это, собственно, ровно то, что и сделано у нас.

Reply

aamonster November 5 2016, 18:29:12 UTC
Не вижу, как включение поля по значению в плюсах могло бы решить проблему утечки для listeners.
Если мы где-то сохранили ссылку на такое поле - она станет некорректной, когда объект умрёт. И, соответственно, если нам нужно гарантировать, что сохранённая ссылка корректна - придётся удерживать в памяти весь объект (привет, COM с его GetOuterUnknown).
Т.е. опять нужна или явная отписка, или weak references.

Reply

gaperton November 5 2016, 23:15:55 UTC
> Не вижу, как включение поля по значению в плюсах могло бы решить проблему утечки для listeners.

Это позволяет автоматически сгенерировать корректный деструктор. Который пройдется по составному состоянию всех виджетов на странице, и рекурсивно отпишет агрегированные объекты от событий. Для этого системе надо отличать композицию от ассоциаций, чтобы не прибить то, что лежит в синглтоне.

Деструктор состояния в свою очередь вызывается автоматически при вынимании виджета из DOM. То есть, все надежно, и явной отписки нет.

Reply

gaperton November 5 2016, 23:23:43 UTC
Ну то есть, для данного примера состояние страницы будет выглядеть примерно так:

state : {
selectedUsers : User.Collection.Refs
}

User.Collection - это конструктор коллекции юзеров. Добавляя к нему Refs - мы получаем коллекцию, которая не пытается брать ownership над своими элементами, и деструктор которой не разрушает объекты внутри нее (но отписывает от событий).

В итоге, когда состояние страницы будет прибито, объекты user внутри синглтона будут живы. Но selectedUsers отпишется от событий, и умрет.

Reply

aamonster November 6 2016, 08:59:08 UTC
Так. Похоже, я запутался.
1. "Добавляя к нему Refs - мы получаем коллекцию, которая не пытается брать ownership над своими элементами" - а как делать enumerate объектов в коллекции, если weakrefs нету? Или мы ходим по всем объектам DOM и проверяем, не у нас ли он лежит? Но это ж ад...
2. Как достигается отсутствие ссылок от юзеров на коллекцию? Просто запрет ссылок на неё? Или перенаправление этих ссылок на родительский объект?

Или всё вообще сводится к "вот этой коллекцией я точно владею, поэтому на деструкторе выкинем из неё все элементы"? Т.е. суть композиции - один флажок, учитываемый деструктором? (а по сути - создание "дерева владения", в котором деструктор вышестоящего объекта обрывает все связи в дереве, причём деструктор даже не настоящий, а вызывается при удалении из DOM?)

P.S. Капча достала. Почему жж-программеры не могут задетектить, что юзер один и тот же (залогинен же) и раз за разом капчу успешно решает?

Reply

gaperton November 6 2016, 19:12:37 UTC
У UI-виджетов во многих фреймворках уже есть деструктор, который вызывается при смене раута и вынимании виджета из DOM. В React это componentWillUnmount, например ( ... )

Reply

aamonster November 6 2016, 21:09:36 UTC
Печально это всё на самом деле. По сути, поверх одной модели владения (ссылки и gc) пришлось накрутить ещё одну, но уже не допускающую циклов.
В reference-counting модели (я за последние годы к ней привык - под macos gc не успел даже попробовать, как его задепрекейтили в пользу arc) всё несколько проще, но, конечно, даны другие способы выстрелить себе в ногу (любимый метод создания циклических ссылок - лямбды [blocks]).

Кстати, не в курсе - текущие реализации js используют чистый gc или reference-counting-based оптимизации применяются (т.е. порой объект может быть убит сразу, как кончились ссылки на него, не дожидаясь прохода gc)?

Reply

gaperton November 7 2016, 02:50:29 UTC
Это все печально неимоверно. Я думал и о счетчике ссылок поверх, который бы включал деструкторы, но решил что не стоит. От явной агрегации много другой пользы - объекты правильно копируются by default, например.

Текущие реализации GC в JS используют mark-and-sweep, V8 использует stop-and-copy. Счетчиков ссылок, насколько мне известно, не использует никто.

В функциональных языках применяется оптимизация известная с LISP машин - однобитные счетчики ссылок. Специально для элементов однонаправленных списков. В JS это не поможет.

Reply

gaperton November 5 2016, 17:55:38 UTC
А вик референсы - да, это хорошее решение. В принципе, в JS они есть.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet

Но не работают в IE. Совсем.

Reply

gaperton November 5 2016, 18:03:47 UTC
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap

Вот это должно как-то работать в IE11. В принципе, на этом можно собрать движок событий - достаточно пропустить все ссылки через WeakMap. И тогда ликов не будет.

Что отличная идея, вопрос только, насколько медленно это будет работать в сравнении с обычными ссылками. Я сделаю экспериментальный движок, посмотрим. Может, будет наоборот быстрее - с ними отписка от событий гораздо проще.

Ну, и поддержку IE10 мы пока убрать не можем.

Reply


Leave a comment

Up