Комментарии 23
Если кто-нибудь знает более удобный инструмент, поделитесь, пожалуйста.
Слабые ссылки — это почти как обычные, только они могут быть собраны в случае нехватки памяти.
Если у вас Node.js, то вы можете иcпользовать node-weak и слабые ссылки, например, для кэширования.
Слабые ссылки не подходят для кеширования. Это не ссылка «ну, если будет не хватать памяти, можешь удалить». Слабые ссылки нужны, чтобы ссылаться на объект, пока он существует. Но если на объект нет ссылок кроме слабых, сборщик мусора должен его удалить вне зависимости от «нехватки памяти».
В java есть weak- и soft- ссылки. Первые работают так, как вы описали, а вторые будут жить до full gc и умрут только в том случае, если этот full gc был вызван по причине, что выделение памяти для нового объекта зафейлилось (т.е. случился мягкий oom).
Да, согласен, пример с кешированием не правильный. Корректным был бы пример про библиотеку, которой нужно ссылаться на пользовательский объект, но не владеть им. (Кмк большая часть кейсов использования слабых ссылок — это различного рода дата-биндинги и всякое прочее зеркалирование объектов.)
И, раз уж заговорили о слабых ссылках, допишу тут вещь, которая ни в доклад ни в доклад не попала. tc39/proposal-weakrefs и node-weak дают возможность писать финализаторы. Это позволяет, например, делать всякие "защитные" механизмы, типа автоматического закрытия файлов/сокетов в ноде и удаления webgl текстур в браузере.
сборщик мусора должен его удалить
Должен удалить в какой момент? При следующем запуске сборщика? А когда будет следующий запуск сборщика?
Тут такой момент, что сборка мусора из текущей спеки вообще ничего не гарантирует, просто потому что ее там нет. Есть пара очень абтрактных предложений в WeakMap/WeakSet (по сути гарантируется только сборка ключей в рамках одного WeakMap/WeakSet), и упоминание в NOTE'ах. Сборка мусора — это деталь имплементации движков.
tc39/proposal-weakrefs должен это изменить и привезти сборку мусора в спеку, а с ней доступность объектов и прочие интересные вещи. Но никакой отдельной гарантии на временя жизни для слабо-доступных объектов по сравнению с просто недоступными объектами там нет. (В текущей версии пропоузала слабо-доступные объекты будут жить, пока их не почистят руками, если я все правильно понял, но в этот момент они уже собраны.)
В реализациях разницы между слабо-доступным и недоступным объектом тоже нет (хотя я могу говорить уверенно только про v8). Кеш через слабую ссылку удалится при первой же сборке поколения, в котором находится кеш.
UPD: извиняюсь, перепутал людей.
Мне-то вы зачем всё это рассказываете?
Потрясающе ) Вы спросили и недовольны, что вам ответили )
Ни вы ни flapenguin так и не ответили, кому и когда должен сборщик мусора.
Цитирую:
сборщик мусора должен его удалить вне зависимости от «нехватки памяти».
В идеале — ссылку на пункт в спецификации JS где чёрным по белому это заявлено.
Начнем с того, что ва́м никто ничего не должен. Если вас не удовлетворил ответ, поблагодарите за потраченное на вас время и переспросите то, что не понятно.
На ваш вопрос «кому и когда должен сборщик мусора» flapenguin ответил в полной мере, потрудитесь прочесть.
2. Комментарий flapenguin не отвечает на мой вопрос. Его «сборка мусора из текущей спеки вообще ничего не гарантирует» и ссылка на «An implementation may impose an arbitrarily determined latency between the time a key/value pair of a WeakMap becomes inaccessible and the time when the key/value pair is removed from the WeakMap.» противоречит вашему изначальному утверждению.
3. Ваша телепатия слаба, комментарий flapenguin я читал.
Кеш через слабую ссылку удалится при первой же сборке поколения, в котором находится кеш.
Если у сборщика нет никаких обязательств когда выполнить эту "сборку поколения, в котором находится кеш" [кто вообще сказал что у сборщика мусора обязаны быть поколения?], у вас нет никаких гарантий когда объект будет удалён.
Позволю себе маленькую поправку:
[методу work] тоже можно задать прототип и вызывать его через new, но таким поведением редко кто пользуется.
Нельзя, методы в ES6 не могут использоваться как конструкторы:
class Foo { bar() {} }
new Foo.prototype.bar(); // TypeError
new (new Foo()).bar(); // TypeError
let o = { bar() { } };
new o.bar(); // TypeError
Я исходил из предположения, что большинство слушателей гораздо лучше знакомы с ES5. Поэтому в примере не настоящий ES6, а "ES6 собранный в ES5 вашим любимым транспилятором" (а еще потому что на слайде мало место). Но об этом, конечно, стоило упомянуть в докладе.
Бтв, конструктор класса это, на самом деле, тоже не совсем обычная функция, у нее, например, нельзя вызывать call
и apply
(спека).
конструктор класса это, на самом деле, тоже не совсем обычная функция, у нее, например, нельзя вызывать call и apply (спека)
Немного проще — конструктор класса нельзя вызывать никак, кроме как через new (собственно, раздел спецификации по ссылке именно об этом и говорит).
Но да, я согласен, что по сути это мелкие придирки. :)
[в таблице] есть еще алгоритм Eden, но про него позже.
Я что-то пропустил или в статье действительно так и нет описания алгоритма Eden? :)
После чистки проблема не решается, так как в памяти остаются дырки. Обратите внимание, что свободных квадратиков 7, но 5 из них мы все еще не можем выделить. Произошла фрагментация и на этом сборка закончилась. Такой алгоритм с дырками называется Mark and Sweep.
Минусы:
Требует сложной логики поиска свободного места, потому что когда в памяти много дырок, то в каждую приходится примерять объект, чтобы понять — подходит он или нет.
Фрагментирует память. Может произойти ситуация, что при свободных 200 Мб память разбита на маленькие кусочки и, как в примере выше, нет цельного куска памяти под объект.
Судя по поведению такой GC используется в FireFox или по крайней мере использовался до 57й версии (новые версии не тестировал пока).
Особенно заметно на 32 бит версиях — при более-менее серьезной нагрузке на браузер через какое-то время возникает очень распространенная ситуация, когда память одновременно как бы есть, но ее как бы и нет. Выделение(резервирование) памяти подходит к 2 ГБ на процесс (лимит для 32 бит систем) — больше выделить нельзя. И не смотря на то, что реально используемый объем памяти (занятой) еще составляет только 1.1-1.5 ГБ браузер практически зависает и проявляет явные симптомы нехватки памяти: не прогружаются какие-то объекты на страницах, не может открыть новую вкладку и т.д.
При этом загрузка процессора доходит до максимума (одно из ядер постоянно занято на 100%). Видимо это как раз сборщик мусора лихорадочно мечется пытаясь найти куда бы впихнуть новые объекты, но из-за фрагментации памяти этого сделать не может. Хотя в принципе еще сотни МБ из выделенного процессу объема в этот момент пустуют.
Да, глядя на эти схемы невольно начинаешь проникаться тем, о чём говорит Дуглас Крокфорд.
garbage.collect()