i18n: Memory Leak when using top-level await before defining computed translations
Environment
- Operating System: Linux
- Node Version: v20.8.1
- Nuxt Version: 3.8.2
- CLI Version: 3.10.0
- Nitro Version: 2.8.1
- Package Manager: npm@10.1.0
- Builder: -
- User Config: app, modules, devtools
- Runtime Modules: @pinia/nuxt@0.5.1, @nuxtjs/i18n@8.0.0-rc.11
- Build Modules: -
Reproduction
I’ve created a minimal reproduction repository to illustrate the problem. To reproduce the issue:
- Clone the repository:
git clone git@github.com:azhirov/nuxt-i18n-pinia-memory-leak.git - Install dependencies:
npm install - Build the project:
npm run build - Run the server:
node .output/server/index.mjs - Use a tool like
ab,siege, or any other utility to send multiple requests. For example:siege -c10 -t30s http://127.0.0.1:3000orab -n 5000 -c 100 http://localhost:3000/ - Check the memory consumption of the process (for example, using the
topcommand).
Describe the bug
I’ve encountered a peculiar memory leak issue related to the simultaneous usage of the @nuxtjs/i18n and @pinia/nuxt modules in a Nuxt 3 project. The problem manifests when an asynchronous method from the Pinia store is called (using await) before a computed property that includes useNuxtApp().$i18n.t(). This results in a memory leak. Interestingly, moving the asynchronous method below the computed property prevents the leak. Additionally, if the $i18n.t() is not used in the computed property, the leak does not occur.
Code with memory leak:
import useFooStore from '~/store/foo';
const fooStore = useFooStore();
await fooStore.loadData()
const text = computed(() => {
const i18n = useNuxtApp().$i18n;
return i18n.t('seventeen');
})
After running the command node .output/server/index.mjs, the server consumes approximately 20 MB of RAM. However, after executing the command siege -c10 -t30s http://127.0.0.1:3000, the memory usage increases to 1.4 GB and remains at approximately this level even after stopping the load.
If you move the await call to the asynchronous method of the store below the computed property, the graph looks like this (the memory leak is significantly reduced, and memory consumption resets to almost the initial level).
I’ve noticed an interesting pattern: the memory leak seems to intensify with an increase in the number of translation files (in the lang directory).
Additional context
A similar issue was mentioned earlier in this comment: https://github.com/nuxt-modules/i18n/issues/2034#issuecomment-1659386170. After updating to version 8.0.0-rc.11, the problem reproduces only when using Pinia. A simple asynchronous function defined within the same component does not trigger the memory leak.
Logs
No response
About this issue
- Original URL
- State: closed
- Created 6 months ago
- Reactions: 2
- Comments: 44 (20 by maintainers)
I have checked several versions of the module for memory leaks. The repository https://github.com/azhirov/nuxt-i18n-pinia-memory-leak was used for testing. Before installing a new version each time, I deleted
package-lock.jsonand thenode_modulesdirectory. Then I built the project and ran it:nuxi build && node .output/server/index.mjsFor load testing, the command
siege -c10 -t30s http://127.0.0.1:3000was used.Here are the results:
8.0.0-rc.5 ✅
No leaks, no errors in console output (
"vue-i18n": "9.5.0")RAM usage graph (click to view)
8.0.0-rc.6 ❌
There is a leak, and there is an error
[nuxt] [request error] [unhandled] [500] Maximum call stack size exceededRAM usage graph (click to view)
8.0.0-rc.7 ❌
There is a leak, and there is an error
[nuxt] [request error] [unhandled] [500] Maximum call stack size exceededRAM usage graph (click to view)
8.0.0-rc.8 ❌
There is a leak, and there is an error
[nuxt] [request error] [unhandled] [500] Maximum call stack size exceededRAM usage graph (click to view)
8.0.0-rc.9 ❌
There is a leak, and there is an error
[nuxt] [request error] [unhandled] [500] Maximum call stack size exceededRAM usage graph (click to view)
8.0.0-rc.10 ❗️
No leaks, but there is an error
[nuxt] [request error] [unhandled] [500] Maximum call stack size exceededRAM usage graph (click to view)
8.0.0-rc.11 ✅
No leaks. No errors. I was surprised here because this version had the issue. I examined the
package-lock.jsonfile and found that a new version of thevue-i18npackage (9.9.1) is now installed.RAM usage graph (click to view)
8.0.0-rc.11 and vue-i18n@9.8.0 ❌
There is a leak. To check, I deliberately installed an old version of
vue-i18nusing the commandnpm i --save vue-i18n@9.8.0. No errors in console output.RAM usage graph (click to view)
i18n-edge@8.0.0-28444362.1cb9e70 ✅
No leaks. Probably because the minimum version of the package is specified in the dependencies:
"vue-i18n": "^9.9.0". No errors in console output.RAM usage graph (click to view)
I might be mistaken, but it seems that the leak was in the
vue-i18npackage, and it is fixed in version9.9.0. Therefore, in the production environment, it is sufficient to specify inpackage.json:No need to install
@nuxtjs/i18n-edge@latest.I’ve checked on my own stand with same problem - no more memory leaks! Total heap size increases when there ara many active request, but then return to normal value fast. Really waiting release of this fix! Thank You!
@kazupon Ah I have used that too, I was hoping
pnpm linkwould work the same without needing to zip and install 😥, my workflow for checking the memory leak is a bit slow.@azhirov No worries, I don’t think the difference between the two reproductions matter much after all.
What’s interesting is that this memory leak doesn’t seem to be present if the translations are in
i18n.config.tsinstead of loading them in files. Still working on debugging this!Thanks for reporting and providing a reproduction!
This sounds similar to https://github.com/nuxt-modules/i18n/issues/2034, I thought I fixed that 😥 hopefully I’ll have time to debug this soon.
Hello to all, we had a problem with a newly push to production Nuxt 3 app. This modification to packages.json made the trick in local. We will deploy a new release of our app soon in prod container.
For context :
So, to conclude, @azhirov : thank you so much mate.
@azhirov Thank you for your thorough testing, this is great!
You’re right, most if not all of the memory leak was fixed in
vue-i18n@9.9.0, a fresh install of@nuxtjs/i18n@^8.0.0should use this version as well (as you noticed withrc.11). There have been a few changes since release so it’s good to see that the edge release is still doing well memory wise in your setup.Will soon publish a patch release with the recommendation to refresh lockfiles when updating to ensure the latest
vue-i18nis installed along with it. After which I’ll close this issue, thanks again for providing your minimal reproduction and this detailed report!Checked on one of the test repositories, everything is fine now. Unfortunately, it will take significantly more time for the others. For now, we have worked around the issue with temporary solutions. I will try to do more testing.
Can you check if you’re still experiencing the leak using the latest edge release? (
npm i -D @nuxtjs/i18n@npm:@nuxtjs/i18n-edge@latest)I made some changes in
vue-i18n(https://github.com/intlify/vue-i18n-next/pull/1677) that should reduce memory usage and it seems the messages are not leaking (as much) anymore. I still don’t think this removes the leak fully, a very small leak is likely still present.https://github.com/nuxt-modules/i18n/pull/2647
Basically, it seems that I found where the leak is. If you do as in my pull request, the leak disappears. It means that a reference is created in ‘messages’ and can’t be destroyed. I spent a lot of time searching, but after the fix, everything started working fine. Unfortunately, due to such a solution, the framework began to work slower, but I think you will figure it out from here.
It seems I managed to localize and fix the issue.
https://github.com/s00d/i18n/tree/fix-leak
In the Nuxt documentation, they recommend using JSON instead of a class. I rewrote your code to import JSON, and the problem disappeared. Therefore, the memory leak is definitely related to generateTemplateNuxtI18nOptions.
Here is the documentation link.
https://nuxt.com/docs/api/kit/templates#examples
Here are my changes.
https://github.com/s00d/i18n/commit/c6e4163d2ca7c00337eb34bfb9539a2de349c606 https://github.com/s00d/i18n/commit/d05a972a12925d2a3bca217312541afc7a432b8b
Please note that this is just a code example, it’s not very functional and triggers warnings due to JSON imports, but I believe it will help in identifying the issue.
Same issue, i have stores before computed properties with t()