Tips for identifying the cause of a memory leak in browser notifications

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?

  1. Allow StackOverflow show notifications in your browser settings
  2. Open the browser task manager (Shift + Esc)
  3. Run the provided code in the developer console
  4. 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)
    }
}

Answer №1

Upon conducting some investigation, I have determined that the Notification class is somehow cached.

https://i.sstatic.net/1SqGW.jpg

https://i.sstatic.net/WxX9H.jpg

I use the term "somehow" because it does not follow the typical caching process. Javascript utilizes a Garbage Collector to remove unused objects from memory, but it seems that instances of the Notification class persist even if they are technically not in active use. Through analyzing the heap allocated objects using my web browser's memory profiler, I observed that the Notification class objects are retained. Attempts to use the delete keyword on these objects only removes the reference and not the actual object. This leads me to believe that the Notification class instances remain in memory due to their ongoing use, and any efforts to release them will only affect the referencing variable.

The most effective method to clear this cache is by refreshing the page. By reloading the page, the memory holding these objects will be cleared. To manage the notification system across page reloads, it is possible to utilize persistent memory caches such as localStorage. To store a value in localStorage upon page reload, you can employ commands like localStorage.getItem('name'); to retrieve an item's value, localStorage.setItem('name', 'value'); to add a new item, and localStorage.removeItem('name'); to delete an item.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ways to retrieve a file from a specific location using fetch/axios?

For my research, I need to utilize certain network APIs such as fetch or axios to access a local file without using the fs module or importing them directly. I attempted to use both fetch and axios but found that they do not support fetching local files, ...

Display HTML content using JavaScript only when a checkbox is selected

Currently, I am updating an HTML form to show additional subsets of questions based on the selection of a "parent" checkbox. The current implementation works well, but I am wondering if there is a more efficient way to achieve this without having to rewrit ...

Problem with extJS portal functionality

Currently, I am utilizing this particular URL for my application: . I attempted to swap out the existing chart in the third column with a bar chart and a pie chart (both of which work fine within panels and windows), but I encountered an "h is undefined" e ...

One of the great features of Next.js is its ability to easily change

At the moment, my dynamic path is configured to display events by their ID [id].js localhost:3000/event/1 But I would like it to be structured as follows: localhost:3000/city/date/title. All of this information is available in the events database, but I&a ...

Verify that each field in the form contains a distinct value

I have a formarray with nested formgroups. How do I ensure that the elements within each formgroup are unique? Here is an example of my form setup: form: FormGroup = this.formBuilder.group({ fields: this.formBuilder.array([]), }); private createField() ...

Tips for selecting React component props based on a specific condition

Here is a React component that I have: <SweetAlert show={this.props.message} success title={this.props.message} onConfirm={this.props.handleCloseAlert}> </SweetAlert> Upon using this component, I receive the following alert ...

Error message: Attempting to access the 'path' property of an undefined variable results in TypeError while utilizing cloudinary services

I am currently attempting to upload a file from React to an Express server, but I keep encountering this error TypeError: Cannot read property 'path' of undefined The method I am using involves React for transferring/uploading the file to the ...

Limit an object to only contain interface properties

Suppose we have the following object: o {a : 1, b : 2} and this interface defined as: interface MyInterface { a : number } We are now looking to create a new object that represents the "intersection" of o and the MyInterface: o2 : {a : 1} The mai ...

Unable to retrieve information from v-for as it returns null data

Currently facing an issue with retrieving data from the database using Axios in Vue.js. I am able to see the data in my database through Vue.js developer tools like this: https://i.stack.imgur.com/n7BRO.png However, when attempting to loop through the dat ...

How can I use jQuery UI to slide a div, while also smoothly moving the adjacent div to take its place?

Wishing you an amazing New Year! I am looking to create a smooth sliding effect for a div when a button is clicked. I want the adjacent div to slide alongside it seamlessly, without any clunky motions or delays. Currently, the adjacent div only moves afte ...

Show the checked items in the table based on the ID value stored in the array

When I click the button labeled Show checked if id values are 1 and 5, I encounter an issue in displaying checked items in the table based on their corresponding id value in the array. Essentially, I want to show the checked items in the table only if thei ...

What exactly is the functionality of this "if" statement that operates without any operators?

I've recently started learning Javascript and I'm currently going through chapter 5 of Eloquent Javascript. In my studies, I encountered a piece of code that is puzzling to me. While I understand the general method and steps of how it works, I&ap ...

Is converting the inputs into a list not effectively capturing the checkbox values?

On my website, I have a div that contains multiple questions, each with two input fields. When a button is clicked, it triggers a JavaScript function to add the input values to a list. This list is then intended to be passed to a Django view for further pr ...

What is the best way to trigger an ajax request when a user selects a tab?

How can I trigger an ajax call when a tab is clicked by the user? What is the best way to handle the HTML response and display it within the tab? How do I bind JavaScript events to the dynamically loaded HTML content? I am familiar with using jQueryUI tab ...

AngularJS factory with local storage functionality

As a newcomer to IonicFrameWork, I decided to try out their "starter tab" template and made some tweaks to the functionality of deleting and bookmarking items from a factory. In my books.js file where the factory is defined, here's a snippet of what ...

Exploring the latest updates in MUI modern version

The MUI documentation suggests using a modern folder with components designed for modern browsers. Is there a way to configure webpack to automatically rewrite imports like import {Box} from "@mui/material" to use the modern version without manually changi ...

Tips on utilizing the useState hook for storing numerous key objects?

Currently, I am working with a candlestick chart for a cryptocurrency that displays data over different timeframes such as 1 minute and 30 minutes. Below is the code snippet that sets the initial state to show a 1-hour chart when a user first visits: const ...

Having trouble with Angular JS $scope.$apply due to an interpolation error displaying "TypeError: Converting circular structure to JSON"?

I have created a specialized angular directive shown below: dirs.directive('sectionInfo', function(){ return { restrict: 'E', templateUrl: 'partials/section-home.html', transclude: true, co ...

Issue with a input element having relative positioning within a flexbox

Objective: Aim to align the middle DIV (MIDDLE) within a flexbox row in the center. Issue: The right element includes an input element with relative positioning. Consequently, the middle DIV element (MIDDLE) is no longer centered but instead shifted to th ...

Creating a Client-side Web Application with Node.js

As I search for a versatile solution to bundle an HTML5 web application (without server dependencies) into a single executable app using node.js and the Linux terminal on Ubuntu, I have experimented with tools like wkpdftohtml and phantomjs. However, these ...