Почему Chrome сохраняет анонимный объект MediaRecorder в памяти?

После попытки понять, почему некоторые объекты моего веб-приложения были сохранены в памяти Chrome, я думаю, что, возможно, я сузил их до случая недоступности в противном случае MediaRecorder объект сохраняется браузером. Пожалуйста, обратите внимание на следующий минимальный пример, который воспроизводит проблему (анализ снимка кучи после согласия поделиться моей камерой и микрофоном, когда обещание возвращается getUserMedia решает).

navigator.mediaDevices.getUserMedia({ 
  video: true,
  audio: true
}).then(function create_media_recorder(stream) {
    new MediaRecorder(stream);
    console.clear();
});

На объект медиа-рекордера ничего не ссылается, и он должен иметь наименьшее время жизни, которое у него когда-либо было, однако он остается в памяти после снимка, который я делаю после очистки консоли (разработчики из Developer Tools рекомендуют очистить консоль, прежде чем принимать снимок кучи, поскольку первый может удерживать объекты, которые в противном случае были бы освобождены).

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

Я не могу найти какие-либо методы в MediaRecorder класс, который указывал бы на меня, можно отделить его от потока или иным образом "закрыть". Если не считать, что на него нет явных или не столь очевидных (например, через слушателей событий) ссылок, я могу только надеяться, что анонимный объект не сохраняется, а такие объекты обычно нет, но MediaRecorder объекты кажутся. Кажется, у меня нет какого-либо рычага, которым можно было бы распоряжаться, так сказать.

На приведенном ниже снимке экрана видно, что объекты, сохраняющие медиа-рекордер, не являются частью моих сценариев, скорее они связаны с некоторым внутренним состоянием браузера:

Снимок экрана панели

Значок окна рядом с объектом, выбранным в столбце "Конструктор", содержит подсказку "Пользовательский объект [доступен] из окна". Приведенный выше фрагмент кода - это единственный код, который я запускаю на вкладке. Почему объект может быть доступен из окна, и если это так, то, безусловно, он не может быть ссылками, которыми я управляю?

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

Я запустил тот же код в Firefox 62.0.2 и там поведение, которое я ожидал - одиночный MediaRecorder Кажется, что созданный мной объект выходит из области видимости (как и должно быть, так как он не должен иметь ссылок на него) вскоре после его создания, и индикатор, указывающий на использование моей веб-камеры, исчезает.

(Chrome версии 69.0.3497.100, x64 в Windows 10)

3 ответа

Решение

Было подтверждено, что это проблема с Chromium (и, косвенно, с Google Chrome и, возможно, с другими производными Chromium, включая Electron):

https://bugs.chromium.org/p/chromium/issues/detail?id=899722

На момент написания этой статьи проблема помечена как «доступная», что, как я полагаю, означает, что она признана и фактически ожидает, что кто-то вмешается и исправит.

Убедитесь, что в настройках вашего браузера не установлен флажок "Сохранить журнал при навигации", в противном случае console.clear() ничего не делает.

https://developer.mozilla.org/en-US/docs/Web/API/Console/clear

РЕДАКТИРОВАТЬ:

Кроме того, я сомневаюсь, что это утечка памяти, так как недоступные объекты автоматически удаляются. Более вероятно, что MediaRecorder сохраняет объекты в глобальной области видимости.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management

"4.3.1 Жизненный цикл и поток информации" должен немного прояснить ситуацию.

https://www.w3.org/TR/mediacapture-streams/

Согласно спецификации:

Считается, что объект MediaStream активен, когда у него есть хотя бы один MediaStreamTrack, который не завершился. MediaStream, который не имеет никаких дорожек или имеет только дорожки, которые закончились, неактивен.

Когда вы создаете новый MediaStream, если вы не остановите все его дорожки, он останется в активном состоянии.

Таким образом, чтобы сбросить этот объект, вам нужно явно избавиться от его объектов MediaStreamTrack, получив ссылку на поток, например:

var myRecorder;
navigator.mediaDevices.getUserMedia({ 
  video: true,
  audio: true
}).then(function create_media_recorder(stream) {
  myRecorder = new MediaRecorder(stream);
  console.clear();
});

var myStream = myRecorder.stream;
myStream.getTracks().forEach(function(el) {
    el.stop()
}

после этого вы увидите, что значок записи исчезает - поток мультимедиа теперь неактивен.

Проверьте эти API для дальнейшего использования

https://developer.mozilla.org/en-US/docs/Web/API/MediaStream

https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack

Другие вопросы по тегам