Где хранятся объекты IDBRequest в памяти? - PullRequest
1 голос
/ 25 апреля 2020

Это может показаться странным вопросом, но я пытаюсь понять, что именно мой код делает с памятью, чтобы сделать его максимально эффективным.

Когда выполняется запрос к базе данных, такой как req = objectStore.getAll( keyRange );, и возвращается объект IDBRequest, а результат предоставляется позднее свойству result объекта, где создается объект? Это так же, как любой другой объект JS, выделенный и выпущенный GC; и переменная req является просто ссылкой на нее, так что после разрыва ссылки G C «знает», что объект недоступен и освобождает память?

Если много таких запросов выполняется более короткий промежуток времени, есть ли способ не использовать дополнительную оперативную память для каждого результата?

Например, интересующий меня процесс - нажатие кнопки вызывает два обещания (одно запись и одно чтение) через Promise.allSettled, который записывает текущее состояние в базу данных, а другой извлекает новые данные и строит из них фрагмент документа. Если оба выполняются, фрагмент заменяет узел в DOM.

Если пользователь быстро щелкает эти данные, каждый read/getAll возвращает IDBRequest с результатом, который представляет собой массив объектов, и это появляется потреблять все больше и больше оперативной памяти, пока G C не запустится. Я могу наблюдать, что память в конце концов освобождается, но мне было интересно, есть ли способ, чтобы этого не произошло. Поскольку я знаю, что это за объекты с точки зрения максимального размера, могу ли я записать IDBRequest в существующий объект, который похож на объект шаблона, и когда-нибудь понадобится только один или два из них, например, один для текущего и один для нового запроса, вместо того, чтобы постоянно добавлять новые объекты, пока G C не выпустит те, которые считаются недоступными?

Спасибо за рассмотрение моего вопроса.


Спасибо за ответ относительно того, где размещен объект IDBRequest и совет относительно избежания утечек памяти. Просто чтобы добавить дальнейшее объяснение того, что я наблюдал и задавался вопросом, возможно ли это, я добавляю эту заметку.

В моем коде не объявлено ни одной глобальной переменной, все существуют в функциях или являются свойствами функционального объекта; и я устанавливаю tem в null при закрытии каждой функции на случай, если пропущу какую-то скрытую ссылку на область действия / закрытие. Получив, наконец, большую часть операций ввода-вывода в indexedDB, я начал думать о том, что произойдет, если пользователь будет работать в моем приложении в течение часа или двух. Будет ли использование памяти постоянно увеличиваться в долгосрочной перспективе, хотя я не наблюдал никаких проблем в течение всего процесса сборки и тестирования?

Я заполнил базу данных 500 пакетами данных, что означает, что для создания нового требуется более одного объекта БД. Узел DOM; это может быть от 15 до 60 объектов на узел, в зависимости от того, что строит пользователь. Итак, я сделал каждый из 500 пакетов, состоящих из 60 объектов, и сделал эти объекты слишком большими по размеру для тестирования, намного больше, чем ожидалось при соответствующем использовании инструмента.

Затем через setInterval, обещания сохранения состояния, получения и сборки вызывались каждые 500 мс от пакета 1 до 500; и я наблюдал за использованием данных только на уровне маро. В результате получается, что в любой момент времени между запусками G C может быть около ста таких пакетов в оперативной памяти. Когда пакеты извлекаются, а узлы создаются и заменяются, использование ОЗУ постоянно увеличивается и уменьшается примерно в пять раз во время обхода от пакета 1 до 500. Максимальный уровень каждого увеличения до сброса немного выше, чем предыдущий. Примерно через 45 секунд или около того после завершения память возвращается примерно к тому, где она была, когда начался setInterval.

Таким образом, к счастью, я не думаю, что есть утечка памяти. Однако использование ОЗУ в значительной степени соответствует описанию в этой статье об использовании пулов объектов. Мне интересны графики под заголовком «Уменьшить отток памяти, уменьшить налоги на сборку мусора» - этот шаблон, который потребляет гораздо больше памяти, чем когда-либо, когда это может быть похоже на второй график, который меньше, уровень и требует меньше G C в общей сложности.

И первый ответ на этот вопрос SO , почти в самом конце, пишет, что это вызывает G C чтобы также отслеживать другие объекты.

Я не уверен, будет ли G C работать при более низком общем объеме оперативной памяти или будет ждать, пока не будет достигнут некоторый максимальный уровень. Конечно, я могу проверить это на своей машине, но это не совсем определенно.

Я не создаю игру, и пауза для запуска G C не проблема; и пользователь никогда не должен кликать 500 пакетов данных за 250 секунд, и никогда не будет 500 пакетов такого смешного размера. Возможно, этот тест был нереальным; но цель состояла в том, чтобы попытаться усилить эффект от использования инструмента в течение длительного периода времени и создания множества мелких объектов повсюду. Даже get / put для незначительного редактирования каждый раз создает новый объект. Это понятия, которые я раньше не рассматривал, а просто сфокусировался на том, как сначала обеспечить точную работу ввода-вывода.

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

Я понимаю, что процесс браузера G C должен облегчить все это, но кажется, что при выполнении так что это многое выводит из-под контроля кодеров; и совет, который я вижу по SO в других вопросах, обычно состоит в том, чтобы не беспокоиться об этом, пока у вас не возникнет проблема. Я в лучшем случае просто любитель, но я бы предпочел понять, что происходит в фоновом режиме, и код с самого начала; и, возможно, с моей стороны есть какое-то упрямство, что независимо от того, насколько мощный процессор и объем оперативной памяти, мой маленький инструмент должен использовать столько ресурсов, сколько необходимо, или я не выполнил свою работу.

Я не надену Не знаю, является ли пул объектов хорошей техникой в ​​любом случае, но даже если бы это было так, кажется, что было бы невозможно получить данные из indexedDB, потому что объект IDBRequest всегда создается заново и никогда не может быть записан в существующий объект.

Еще раз спасибо за объяснение.

1 Ответ

0 голосов
/ 26 апреля 2020

Свойство результата объекта IDBRequest хранит данные в памяти, как и любой другой объект. Когда ничто не ссылается на объект запроса, память восстанавливается. Нет способа не использовать дополнительную память для каждого нового результата. Выделение - это получение памяти. Политика

Chrome заключается в том, что хранение вещей в виртуальной памяти не является проблемой, пока не возникнет конфликт. Вам не следует беспокоиться о чрезмерном использовании памяти, пока не будет доказательств того, что это влияет на производительность. В большинстве случаев это не так.

Однако вы можете посмотреть, где в вашем коде сохранены ссылки на объекты запроса. Если вы будете хранить ссылки на них вечно, то эти объекты никогда не будут освобождены и не подлежат восстановлению. Очень похоже на старую ошибку IE со слушателями событий, которая является формой утечки памяти.

Безошибочный, надежный способ избежать такого поведения - просто использовать переменные в функциях, а не глобальные переменные. Переменные для каждого вызова функции обычно восстанавливаются при выходе из области видимости, когда вызов функции завершается, и при этом не нужно много думать, и нет явного кода, который пытается микроуправлять чем-то, что уже удалось вам. Например, нет необходимости объявлять все переменные как let вместо const и устанавливать value = undefined; или delete value; после каждого использования переменной. Поэтому я бы посмотрел на ваш код и посмотрел, где вы храните ссылки на переменные за пределами срока действия функции, которая их создала. Это виновники.

...