DEV Community

Cover image for How to Prevent Memory Leaks in Angular
Suliman Munawar khan
Suliman Munawar khan

Posted on

How to Prevent Memory Leaks in Angular

Memory leaks are one of the most common performance issues in Angular applications. They occur when your application holds references to resources that are no longer needed, preventing the JavaScript garbage collector from freeing up memory. Over time, memory leaks can slow down your app, increase load times, and cause crashes, especially in large or long-running applications.

In this blog post, we will explore the main causes of memory leaks in Angular and share practical strategies to prevent them.

1. Understanding Memory Leaks in Angular

A memory leak happens when memory that is no longer needed by the application is not released. In Angular, common sources include:

  • Unsubscribed Observables
  • Detached DOM elements
  • Timers or intervals left running
  • Long-lived services holding unnecessary data

Memory leaks can be subtle and difficult to detect because your application might appear to work correctly at first. Tools like Chrome DevTools and Angular DevTools can help track memory usage over time.

2. Common Causes of Memory Leaks in Angular

a. Unsubscribed Observables

Angular applications rely heavily on RxJS Observables for handling asynchronous data, such as HTTP requests or user interactions. Failing to unsubscribe from Observables can prevent components from being garbage collected.

export class ExampleComponent implements OnInit, OnDestroy {
  dataSubscription!: Subscription;

  ngOnInit() {
    this.dataSubscription = this.dataService.getData().subscribe(data => {
      console.log(data);
    });
  }

  ngOnDestroy() {
    this.dataSubscription.unsubscribe(); // Important!
  }
}
Enter fullscreen mode Exit fullscreen mode

Best Practices:

  • Use takeUntil with a Subject to handle multiple subscriptions.
  • Use the async pipe in templates to automatically manage subscriptions.
  • Avoid manual subscriptions if possible.

b. Detached DOM Elements

Sometimes Angular components remove DOM elements from the view but retain references to them in the component class or service. This prevents garbage collection.

Example:

private elementRef: HTMLElement;

ngOnInit() {
  this.elementRef = document.getElementById('some-element')!;
}
Enter fullscreen mode Exit fullscreen mode

If elementRef is not cleared when the component is destroyed, the memory remains occupied.

Solution:

  • Avoid storing raw DOM elements directly.
  • Use Angular's Renderer2 or template references (@ViewChild) properly.

Clear references in ngOnDestroy.

c. Timers and Intervals

JavaScript setInterval or setTimeout can keep running even after a component is destroyed.

ngOnInit() {
  this.intervalId = setInterval(() => {
    console.log('Running...');
  }, 1000);
}

ngOnDestroy() {
  clearInterval(this.intervalId);
}
Enter fullscreen mode Exit fullscreen mode

Always clean up timers in the ngOnDestroy lifecycle hook.

d. Long-Lived Services Holding Data

Singleton services that hold references to large data arrays or objects can cause memory leaks if those references are never cleared.

Example:

@Injectable({ providedIn: 'root' })
export class DataService {
  cachedData: any[] = [];
}
Enter fullscreen mode Exit fullscreen mode

Solution:

  • Clear or reset service data when it is no longer needed.
  • Use lazy-loaded services instead of singleton services for data that is not globally required.

3. Tools to Detect Memory Leaks

  • Chrome DevTools: Use the Memory tab to take heap snapshots and find detached nodes.
  • Augury / Angular DevTools: Helps visualize component lifecycles and detect potential memory issues.
  • RxJS Debugging Tools: Use operators like tap or finalize to track subscriptions.

4. Best Practices to Prevent Memory Leaks

1- Use async Pipe: Automatically unsubscribes from Observables in templates.

<div *ngIf="data$ | async as data">{{ data.name }}</div>
Enter fullscreen mode Exit fullscreen mode

2- Use takeUntil for multiple subscriptions

private destroy$ = new Subject<void>();

ngOnInit() {
  this.dataService.getData()
    .pipe(takeUntil(this.destroy$))
    .subscribe(data => console.log(data));
}

ngOnDestroy() {
  this.destroy$.next();
  this.destroy$.complete();
}
Enter fullscreen mode Exit fullscreen mode

3- Avoid storing DOM references directly; prefer Angular template references or Renderer2.
4- Clean up timers and intervals in ngOnDestroy.
5- Be cautious with global services; reset data when not needed.
6- Avoid circular references between components, services, or data structures.

5. Conclusion

Memory leaks in Angular may seem harmless initially, but over time they can seriously degrade application performance. The key is to be proactive:

  • Unsubscribe from Observables
  • Clear intervals and timers
  • Avoid unnecessary references in services and components
  • Regularly profile your app using memory tools

By following these best practices, you can ensure your Angular applications remain fast, responsive, and free of memory issues.

Top comments (0)