I am looking to implement browser notifications in a browser extension. However, I have noticed that the memory usage does not decrease after closing the notification. Can someone explain why this may be happening?
- Allow StackOverflow show notifications in your browser settings
- Open the browser task manager (Shift + Esc)
- Run the provided code in the developer console
- Monitor the memory usage of the tab
let count = 0
let intervalId = null
Notification.requestPermission().then((result) => {
console.log(result)
intervalId = setInterval(showNotification, 10e3)
});
function showNotification() {
count += 1
if (count == 5) {
clearInterval(intervalId)
console.log('finish')
}
for (let i = 0; i < 3; i++) {
let n = new Notification("My Great Song", {
icon: 'https://i.redd.it/v05doii2jwp31.jpg?t=' + Date.now(),
requireInteraction: true,
});
let timeoutId = setTimeout(() => {
n.close()
n = null
clearTimeout(timeoutId)
}, 5e3)
}
}
In my testing, the memory usage goes up from 90mb to 200mb after running the code and never decreases.
I intentionally chose an icon with a large size to demonstrate a possible memory leak. The same issue occurs with a small-sized icon, just requiring more time and iterations.
If returned to the context of a browser extension, the problem persists. The service worker never closes as it needs to listen to websockets. After some notifications, the memory usage increases indefinitely.
In the memory dev tools, all JS VM instances are less than 4-6mb. Therefore, most of the memory is consumed by notifications that have already been closed.
// content.ts
async function onNotifyAboutStream(stream: NotificationStream) {
let streamInfo = (await Client.getStreamInfo(stream.channelPath)).body
BackgroundClient.showNotification(stream.channelPath, {
title: streamInfo.user.displayName,
message: streamInfo.title,
iconUrl: streamInfo.user.avatarUrl,
type: 'basic',
requireInteraction: true,
})
}
// background.ts
chrome.runtime.onMessage.addListener(onMessageReceived)
function onMessageReceived(message: Message<any>, sender: chrome.runtime.MessageSender) {
if (message.type == RuntimeMessageType.ShowNotificationEvent) {
onCreateNotification(message.data)
}
}
async function onCreateNotification(data: any) {
chrome.notifications.create(data.notificationId, data.notificationOptions)
const notificationId = data.notificationId
const seconds = await settingLiveStorage.instance.autoCloseNotificationAboutStreamSeconds.value()
if (seconds > 0) {
setTimeout(() => chrome.notifications.clear(notificationId), seconds * 1000)
}
}