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
Run server manually
Use this recipe for any server performance tests, results will be more stable than with start-prod command
Before, you need to make a production build:
tramvai build <appName>
After, with default options, application server bundle will be placed here - dist/server/server.js, and client code in dist/client directory.
Use this command to run application server:
DANGEROUS_UNSAFE_ENV_FILES='true' DEV_STATIC='true' ASSETS_PREFIX='http://localhost:4000/dist/client/' node --inspect dist/server/server.js
About env variables:
DANGEROUS_UNSAFE_ENV_FILESforce server to read env variables fromenv.development.jsDEV_STATICforce server to run static server on4000port (all folders from current directory will be served)ASSETS_PREFIXpoints to client code folder on static server
Run start-prod command
Fastest way to run production server, but not suitable for performance tests due to inaccuracies
- You may use either
startorstart-prodcommand to profile your app, but keep in mind thatstartruns app in dev-environment that leads to higher memory consumption and additional code that may distract you from analyzing core logic of the app. Howeverstartis 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/cliyou can pass a special flag--debugand pass it either to thestartorstart-prodcommand - You may pass any additional environment variables when calling cli commands as usual. For example, you may pass flag
HTTP_CLIENT_CACHE_DISABLEDto 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-prodwith 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