Memory leak
In case you are facing critical errors for the server like FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
than this is probably caused by memory leak in your app.
Local profiling
To find out root cause of the problem you need to analyze memory allocation on server over time.
Start the app
- You may use either
start
orstart-prod
command to profile your app, but keep in mind thatstart
runs app in dev-environment that leads to higher memory consumption and additional code that may distract you from analyzing core logic of the app. Howeverstart
is preferred when you need to make code changes and you do not need to get the exact values of memory usage as for the prod-environment. - Using
@tramvai/cli
you can pass a special flag--debug
and pass it either to thestart
orstart-prod
command - You may pass any additional environment variables when calling cli commands as usual. For example, you may pass flag
HTTP_CLIENT_CACHE_DISABLED
to disable http cache. - To pass additional flags to the running nodejs instance you may use env
NODE_OPTIONS
. E.g., if you want to limit the heap memory for the running server passNODE_OPTIONS="--max-old-space-size=256"
- If you are profiling using
start-prod
with different env values without code changes you can use start-prod command that will reuse previous builds, e.g.tramvai start-prod -t none app --debug
Use the DevTools
After starting the app in debug mode you can open Chrome DevTools to be ready to take some profiling.
You may read more about how to profile memory leaks with Chrome in next links:
- https://medium.com/@basakabhijoy/debugging-and-profiling-memory-leaks-in-nodejs-using-chrome-e8ece4560dba#:~:text=Fire%20up%20the%20chrome%20browser
- https://developer.chrome.com/docs/devtools/memory-problems/#summary
Test requests
Most of the time memory leaks are happens for every request, so you need to do some request.
- Using browser go to the page that is handled by you app
- Use any additional tools to make a bunch of requests, e.g. autocannon
What to look
After you've started the app and took memory snapshots or memory allocations look for the data that stays in memory when it shouldn't.
ChildContainer
In context of the tramvai app look for the ChildContainer
first as it is created for every request and contains the whole Request DI instance that consumes a lot of memory. It should be collected by the GC after request end, but sometimes some code may prevent it from collecting.
Summary
- Start the app
- Start the DevTools
- Check memory usage on start and take the initial memory snapshot
- Make some test requests
- Take another memory snapshot
- Compare two snapshots and look for the leaks or unusual memory consumption
Example
- Start app in prod-mode
yarn tramvai start-prod travelaviasearch --debug
- Start Chrome DevTools
- Take the memory snapshot
- Execute requests with
autocannon -c 20 -d 60 localhost:3000/travel/flights/
- Click the button
Collect garbage
- Take another memory snapshot
- Compare two snapshots
- If you want to test app with other envs stop the server and close the DevTools, then run it again with
HTTP_CLIENT_CACHE_DISABLED=true MOCKER_ENABLED=true NODE_OPTIONS="--max-old-space-size=256" yarn tramvai start-prod -t none travelaviasearch