Memory leaks in Angular often occur when observables are not properly unsubscribed. Over time, this can lead to sluggish performance and unexpected app behavior. This guide shows how to fix and prevent such leaks.
1. Understand the Problem
- Angular uses RxJS Observables for async operations like HTTP calls, event listeners, and forms.
- Leaving subscriptions open keeps components in memory even after they are destroyed.
2. Use the Async Pipe for Automatic Unsubscription
Instead of manually subscribing, use the async pipe in templates:
@Component({
selector: 'app-example',
template: `<div *ngIf="data$ | async as data">{{ data.name }}</div>`
})
export class ExampleComponent {
data$ = this.dataService.getData();
}
- Automatically unsubscribes when the component is destroyed.
- Cleaner and safer than manual subscription.
3. Use takeUntil with a Subject
For manual subscriptions, implement a destroy$ pattern:
export class ExampleComponent implements OnInit, OnDestroy {
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();
}
}
- Ensures all subscriptions are cleaned up when the component is destroyed.
- Works for multiple subscriptions in a single component.
4. Unsubscribe in ngOnDestroy
If you don’t use takeUntil, you must manually unsubscribe:
private subscription: Subscription;
ngOnInit() {
this.subscription = this.dataService.getData()
.subscribe(data => console.log(data));
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
- Avoids retaining component instances in memory.
5. Avoid Subscribing in Loops or Nested Subscriptions
- Nested subscriptions make memory management hard.
- Use RxJS operators like
switchMap,mergeMap, orconcatMapto flatten observable chains.
this.route.params.pipe(
switchMap(params => this.dataService.getData(params['id']))
).subscribe(data => console.log(data));
6. Monitor Memory Usage
- Use Chrome DevTools → Memory tab to detect leaks.
- Take heap snapshots to ensure components are released after destruction.
7. Best Practices Summary
- Prefer
asyncpipe whenever possible. - Use
takeUntilfor multiple manual subscriptions. - Avoid nested subscriptions.
- Always unsubscribe in
ngOnDestroyif needed. - Regularly profile your app for memory leaks.
Applying these practices prevents memory leaks, ensures smooth performance, and improves maintainability.
Citations
Internal: https://savanka.com/category/savanka-helps/
External: http://angular.dev/