oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
74.3k stars 2.78k forks source link

Memory leak on Nuxt SSR #14389

Open tilenpirih opened 1 month ago

tilenpirih commented 1 month ago

What version of Bun is running?

1.1.29

What platform is your computer?

windows WSL - docker

What steps can reproduce the bug?

  1. Create empty nuxt project. You can also clone my repository of a minimal reproduction.
  2. Create dockerfile
    
    FROM oven/bun:1.1.29 AS base

WORKDIR /usr/src/app FROM base AS build ENV NODE_ENV=production

COPY . /usr/src/app WORKDIR /usr/src/app RUN bun install RUN bun run build

FROM base AS app

COPY --from=build /usr/src/app/.output /prod/app WORKDIR /prod/app

EXPOSE 3000

CMD [ "bun", "run", "server/index.mjs" ]

3. Run project in the docker
`docker build -t memoryLeak .`
and 
`docker run -p 3000:3000 memoryLeak`

4. Visit the page multiple times. You can use a tool like [OHA ](https://github.com/hatoo/oha) to make a lot of requests. And run a command
`oha -c 2 -n 10000 --disable-keepalive  http://localhost:3000`

5. in the other console type 
`docker stats [container name]`
You can see memory usage
![Image](https://github.com/user-attachments/assets/6a3faf33-f3b7-476e-a9ba-8fe591615fb1)
after 10000 requests
![Image](https://github.com/user-attachments/assets/9bc9ab3b-f1f5-46e4-96df-3248779bfe1e)
after 100000 requests
![Image](https://github.com/user-attachments/assets/8aa2f593-918b-44a8-8afb-8c8baefbbccf)

### What is the expected behavior?

If you edit dockerfile to run app with a Node instead of bun

FROM node:20-alpine AS base WORKDIR /usr/src/app FROM base AS build ENV NODE_ENV=production COPY . /usr/src/app RUN npm install RUN npm run build

FROM base AS app COPY --from=build /usr/src/app/.output /prod/app WORKDIR /prod/app

EXPOSE 3000 CMD [ "node", "server/index.mjs" ]



Memory usage in node after 100000 requests
![Image](https://github.com/user-attachments/assets/a16acddf-a00a-42fd-a459-1c1cde2e309f)

The difference is obvious.

### What do you see instead?

_No response_

### Additional information

In package.json in scripts you can put
`"debug:bun": "bun run build && bun --inspect .output/server/index.mjs"`

and when you run `bun run debug:bun` in console you will see a URL for inspection. It could help with debugging the process, creating snapshots, etc...
Jarred-Sumner commented 1 month ago

My guess is the socket object in our node:http imlementation needs to do some additional cleanup work that it is not currently doing.

In #14384:

 protectedObjectTypeCounts: {
    Promise: 20001,
    UnlinkedProgramCodeBlock: 32,
    UnlinkedModuleProgramCodeBlock: 26,
    Function: 9,
    DebugHTTPServer: 1,
    GlobalObject: 1,
    Timeout: 1,
  },

In main:

{
  objectTypeCounts: {
    Object: 575954,
    Function: 436286,
    Array: 361073,
    string: 232655,
    JSLexicalEnvironment: 173841,
    BufferList: 40003,
    GetterSetter: 28880,
    Promise: 24955,
    "Immutable Butterfly": 23656,
    Headers: 20002,
    Request: 20001,
    Response: 20001,
    ProxyObject: 18242,
    FunctionRareData: 13504,
    AsyncFunction: 13189,

Note how in both cases, the Promise and the Headers/Request/Response are all still there. Something is keeping it alive forever. It's probably not emitting the close event.

tilenpirih commented 1 month ago

Any estimations when this could be resolved? IMO memory leaks and stability should be very high priority.

scottix commented 1 month ago

Does it make any difference if you set nitro preset in your nuxt config

  nitro: {
    preset: 'bun'
  },
tilenpirih commented 1 month ago

This is ram usage after 100000 requests and it seems in a normal range. It's still 10x more compared to npm so there is probably still some room for improvements. But atleast it's solve me headaches with memory leaks for now. Image