#bun memory usage in production

1 messages ยท Page 1 of 1 (latest)

junior bridge
#

I've deployed a very small microservice written in typescript running with bun to production and I've noticed that it's using ~600mb memory after a few days. It starts out only using ~150mb but slowly starts climbing up in memory usage. The service deals with at most a few request per day, but even over periods with no requests, memory usage still climbs. This microservice runs elysiajs with just a few (2) routes and connects to a psql database using drizzle.

I have a very similar separate microservice that handles a lot more requests running with node.js, and it's only consuming 70mb.

Any pointers on how to debug the memory usage? can provide more info if needed.

wintry pond
#

it's possible its a leak in bun itself, but it's hard to say without seeing code to reproduce it

flat cobalt
#

or just anywhere

junior bridge
# flat cobalt when ur querying drizzle, is there any very large objects/arrays?

max array size is 50 objects that aren't too big,
for some context, every time there's a request, it starts some batch processing by grabbing 50 entries from db, then does some work involving network requests, and then grabs the next 50, etc etc

but there have been times where the memory usage would grow even though it's received no requests, so no database queries and no large arrays. other than what I mentioned, there's no other tasks that this service does atm, nothing happening in background.

junior bridge
flat cobalt
# junior bridge thanks will take a look at that ๐Ÿ‘
import { isDevelopment } from "./helpers/stage";

function getMemoryUsage() {
  return process.memoryUsage().rss / 1024 / 1024;
}

const start = getMemoryUsage();

setInterval(() => {
  Bun.gc(true);

  const diff = getMemoryUsage() - start;
  if (diff > 10) {
    console.error(`Memory Diff: ${diff} MB`);
  } else if (isDevelopment()) {
    console.log(`Memory Diff: ${diff} MB`);
  }
}, 60000);
#

You can use that as an idea to help you debug

junior bridge
#

what's the best way to load the heap dumps on non-macos machines?
tried using Epiphany (a webkit based browser) and it froze trying to load the json.

here's the memory usage over 2 days, and in those 2 days, no requests were recieved other than healthchecks (which is simply just a GET /heath, returns 200 "OK!")

rapid rampart
#

where did you deploy the app? some people have problems with railway; switching cloud providers solved it

junior bridge
#

interestingly, after generating the heap snapshot and printing the heap stats, the memory usage dropped ~30mb down to 368mb

#

after forcibly running a Bun.gc, reported heapSize and heapCapacity is much smaller and container memory usage has dropped down to 290.24mb

#

so seems the "solution" may be to just run Bun.gc every once in a while.

junior bridge
crisp horizonBOT
#

๐Ÿ› ๐Ÿ”ด #8897 in oven-sh/bun by Jarred-Sumner opened <t:1707915088:R>
Implement a version of vm.performOpportunisticallyScheduledTasks / JSC::IncrementalSweeper integrated into Bun's event loop

wintry pond
#

this issue aims to address that

grim nimbus
#

I tried the same thing with the code below to see if it's gonna work.

server.get('/gc', async () => {
  const heap = heapStats();
  const start = getMemoryUsage()
  logger.info(`[Cron] Running Bun GC... Starting at ${colors.white(`${start} MB`)}...`)
  Bun.gc(true)
  const diff = getMemoryUsage() - start;
  logger.info(`[Cron] Bun GC has been completed. Memory usage has been reduced by ${colors.white(`${diff} MB`)}...`)

  return {
    startMemory: start,
    endMemory: getMemoryUsage(),
    diffMemory: diff,
    heap: heap
  }
})

But my results are not improved at all. Just around -10 to -40 MB reduction when I run Bun.gc(true). From what I can see there is some objects with a lot of instances such as

  • UnlinkedFunctionExecutable: 17_862
  • JSLexicalEnvironment: 40_017
  • Function: 55_073
  • string: 39_053
  • ShellInterpreter: 8_707
  • Uint8Array: 17_508
  • Object: 28_029
  • Structure: 23_342

For your knowledge, I do not use forEach (which when combined with promises can use more RAM)