0
0
AngularDebug / FixBeginner · 4 min read

How to Prevent Memory Leak in Angular: Best Practices

To prevent memory leaks in Angular, always unsubscribe from observables and event listeners when components are destroyed, typically inside the ngOnDestroy lifecycle hook. Using async pipe or takeUntil operator helps manage subscriptions automatically and keeps your app memory efficient.
🔍

Why This Happens

Memory leaks in Angular happen when subscriptions to observables or event listeners are not properly cleaned up. This causes the app to keep references to components or services even after they are no longer needed, wasting memory and slowing down the app.

typescript
import { Component, OnInit, OnDestroy } from '@angular/core';
import { interval, Subscription } from 'rxjs';

@Component({
  selector: 'app-leaky',
  template: '<p>Leaky Component</p>'
})
export class LeakyComponent implements OnInit, OnDestroy {
  private subscription!: Subscription;

  ngOnInit() {
    this.subscription = interval(1000).subscribe(val => {
      console.log('Tick', val);
    });
  }

  // Missing ngOnDestroy to unsubscribe
  ngOnDestroy() {
    // Intentionally left blank to show missing unsubscribe
  }
}
Output
Console logs keep printing even after component is destroyed, causing memory to grow.
🔧

The Fix

To fix memory leaks, unsubscribe from observables in the ngOnDestroy lifecycle hook. Alternatively, use the async pipe in templates or the takeUntil operator in code to manage subscriptions automatically.

typescript
import { Component, OnInit, OnDestroy } from '@angular/core';
import { interval, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

@Component({
  selector: 'app-fixed',
  template: '<p>Fixed Component</p>'
})
export class FixedComponent implements OnInit, OnDestroy {
  private destroy$ = new Subject<void>();

  ngOnInit() {
    interval(1000)
      .pipe(takeUntil(this.destroy$))
      .subscribe(val => {
        console.log('Tick', val);
      });
  }

  ngOnDestroy() {
    this.destroy$.next();
    this.destroy$.complete();
  }
}
Output
Console logs stop when component is destroyed, preventing memory leaks.
🛡️

Prevention

Always unsubscribe from subscriptions in ngOnDestroy or use Angular's async pipe in templates to handle it automatically. Use the takeUntil operator with a Subject to manage multiple subscriptions cleanly. Avoid creating long-lived subscriptions inside components without cleanup. Use linting tools like rxjs-angular to warn about missing unsubscriptions.

⚠️

Related Errors

Other common issues include not cleaning up event listeners added with Renderer2 or native DOM methods, which also cause leaks. Forgetting to unsubscribe from Router events or NgZone subscriptions can cause similar problems. Always pair resource allocation with cleanup.

Key Takeaways

Always unsubscribe from observables in ngOnDestroy or use async pipe to avoid leaks.
Use takeUntil with a Subject to manage multiple subscriptions cleanly.
Avoid long-lived subscriptions without cleanup inside components.
Lint your code to catch missing unsubscriptions early.
Clean up event listeners and other resources to prevent memory leaks.