• Level Up Coding
  • Posts
  • LUC #12: The Silent Performance Killer: Frontend Memory Leaks

LUC #12: The Silent Performance Killer: Frontend Memory Leaks

How to combat memory leaks in web applications

Welcome back to another edition of Level Up Coding’s newsletter.

In today’s issue:

Read time: 6 minutes

Understanding and Addressing Frontend Memory Leaks

As applications get more complicated and powerful, there is an increasing need to improve performance. To help meet performance goals engineering teams have turned their attention to improving system inefficiencies, such as memory leaks.

Garbage collection is an important component in memory management. It is an automated process that identifies and frees up memory that's no longer in use by the application. Memory leaks result from poorly managed memory allocation. When memory is not properly freed after it is used, leaks occur which causes unnecessary resource consumption.

Frontend memory leaks can have a significant impact on the performance of web applications. They can cause pages to load slowly, use up unnecessary memory, and occasionally cause crashes. They can be a serious problem in single-page applications (SPAs) where pages remain in the browser for extended periods, allowing memory leaks to build up.

Memory leaks can be caused by various factors, but some common culprits include the following:

  • Uncleared event listeners: Event listeners are attached to elements in the DOM, forgetting to remove these listeners prevents the element from being garbage collected. This means that the element will continue to consume resources, even if they’re no longer part of the DOM.

  • Out-of-scope references: Closure functions that refer to variables outside of their scope keep these variables in memory. Memory leaks occur if references to objects are not cleared.

  • Long-lived variables: Variables that contain large objects should be cleared once they're no longer needed to limit unnecessary memory usage.

  • Lingering resources: Open connections or streams to external resources can lead to a considerable amount of resource consumption.

Detecting memory leaks is a difficult challenge. Browser developer tools such as memory profilers can help identify areas that need the most attention. These tools have advanced capabilities to help further investigate potential memory leaks, such as capturing heap snapshots and detailed memory allocation tracking.

Monitoring tools should be used to track trends and identify spikes in memory usage and drops in performance. Advanced tools provide garbage collection insights that let you know how often the garbage collector process runs, and how much memory is freed up each time.

The best way to avoid memory leaks is to set up processes that prevent them from reaching production. Thorough code reviews and testing are key lines of defense. Load tests are particularly helpful as memory leaks tend to become more apparent during high levels of load.

To effectively catch memory leaks during code reviews, developers must have a solid understanding of the best practices for avoiding them. Below are some key approaches to ensure optimal memory usage and prevent potential issues:

  • Clear event listeners once they are no longer needed.

  • Avoid global variables.

  • Release connections or streams to external resources when they are no longer in use.

  • Clear large data structures and remove their references.

Improving memory management and monitoring for memory leaks can lead to better, more reliable web applications that deliver a seamless user experience while minimizing resource wastage.

Load balancers vs reverse proxies (recap)

  • Load balancers are concerned with routing client requests across multiple servers to distribute load and prevent bottlenecks. This helps maximize throughput, reduce response time, and optimize resource use.

  • A reverse proxy is a server that sits between external clients and internal applications. While reverse proxies can distribute load as a load balancer would, they provide advanced features like SSL termination, caching, and security. Reverse proxies are more concerned with limiting and safeguarding server access.

  • Whilst load balancers and reverse proxies possess distinct functionalities, in practice the lines can blur, as many tools act as both a load balancer and reverse proxy.

S.O.L.I.D principles (recap)

SOLID represents five principles of object-oriented programming. Whether or not you use OOP, knowing these principles gives you a lens into the foundations of clean code which can be applied to many areas of programming.

  • Single Responsibility Principle (SRP): Each unit of code should only have one job or responsibility. A unit can be a class, module, function, or component. This keeps code modular and removes the risk of tight coupling.

  • Open-closed Principle (OCP): Units of code should be open for extension but closed for modification. You should be able to extend functionality with additional code rather than modifying existing ones. This principle can be applied to component-based systems such as a React frontend.

  • Liskov Substitution Principle (LSP): You should be able to substitute a base class with its subclass without altering the ‘correctness’ of the program.

  • Interface Segregation Principle: Provide multiple interfaces with specific responsibilities rather than a small set of general-purpose interfaces. Clients shouldn’t need to know about the methods & properties that don't relate to their use case. This decreases complexity and increases code flexibility.

  • Dependency Inversion Principle (DIP): You should depend on abstractions, not on concrete classes. Use abstractions to decouple dependencies between different parts of the systems. Direct calls between units of code shouldn’t be done, instead interfaces or abstractions should be used.

Edge computing vs cloud computing (recap)

  • In cloud computing, computation and data storage happen in a centralized location, with cloud service providers in charge of managing the computer resources.

  • Edge computing is a distributed approach to data storage and task processing. By placing servers on the "edge" of the network or on the actual devices, it moves computing closer to where it is needed.

  • Edge computing and cloud computing are both great options, but which is best for you will depend on the requirements of your application.

That wraps up this week’s issue of Level Up Coding’s newsletter!

Join us again next week where we’ll explore what is quantum computing, lists vs tuples in Python, and components of Docker.