New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SSR - memory leak #1864
Comments
Hi! Are you using family utils? There's a known issue #366 |
Yes, I use I did not found any way to release the memory, but I solved that issue by delegating the render part to the pool of fork processes, once the process exceed the allowed memory, it is killed and replaced by a new process. Simplier but not so efficient would be to create a process for each request, render and kill it afterwards, but this come with a maintenance cost. |
I was able to get rid of memory leak within two steps:
diff --git a/node_modules/recoil/cjs/index.js b/node_modules/recoil/cjs/index.js
index 116fe1d..e36121c 100644
--- a/node_modules/recoil/cjs/index.js
+++ b/node_modules/recoil/cjs/index.js
@@ -9180,3 +9180,29 @@ exports.waitForAll = Recoil_index_18;
exports.waitForAllSettled = Recoil_index_19;
exports.waitForAny = Recoil_index_17;
exports.waitForNone = Recoil_index_16;
+exports.useStoreRef_SSR = useStoreRef;
+
+function releaseStore(store) {
+ const state = store.getState()
+ state.knownAtoms.forEach((node) => {
+ releaseNode(store, state.currentTree, node)
+ })
+ state.knownSelectors.forEach((node) => {
+ releaseNode(store, state.currentTree, node)
+ })
+}
+
+exports.releaseStore_SSR = releaseStore and updated my code for doing SSR, async function renderApp({ req, state }: SSRInput['payload']): Promise<SSROutput['payload']> {
const sheet = new ServerStyleSheet()
let storeRef: { current: RecoilStore }
try {
// this block was added
const AppWrapper = () => {
storeRef = useStoreRef_SSR()
return <App />
}
const app = (
<Router hook={staticLocationHook(req.path)}>
<RecoilRoot initializeState={initStore(state)}>
<AppWrapper />
</RecoilRoot>
</Router>
)
const appHtml = renderToString(sheet.collectStyles(app))
const stylesHtml = sheet.getStyleTags()
const helmet = Helmet.renderStatic()
const headHtml = [
helmet.title.toString(),
helmet.meta.toString(),
helmet.script.toString(),
helmet.link.toString()
]
.filter(Boolean)
.join('\n')
return {
head: headHtml,
style: stylesHtml,
body: appHtml
}
} finally {
sheet.seal()
// this line was added
releaseStore_SSR(storeRef!.current)
}
} Would you think that there is a better approach, ideally without patching the library? @mondaychen |
Hello, firstly I would like to thank you for this fantastic tool.
Recently I have experienced a memory leak during SSR.
After I sent a response to the client, I have observed (via NodeJS debugger) that the Recoil state was not being freed.
The image above depicts a memory snapshot after all requests have been served. The garbage collector has been explicitly called after every request (just for this test scenario). The memory usage increases with every request, leading to a crash of the whole server.
Example SSR code:
The text was updated successfully, but these errors were encountered: