Skip to content

Instantly share code, notes, and snippets.

@apowers313
Created November 9, 2020 03:54
Show Gist options
  • Save apowers313/cee96b41e1f3ba272b214fc7e1c983bb to your computer and use it in GitHub Desktop.
Save apowers313/cee96b41e1f3ba272b214fc7e1c983bb to your computer and use it in GitHub Desktop.
Emscripten Memory Leak on node.js
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("this is a test\n");
}
let factory = require("./build/test.js");
const RESTART_WAIT = 10;
const BYTES_PER_KB = 1024;
let runCount = 0;
// create the emscripten Module
function createModule() {
return {
// undocumented emscripten function; called right before completion of the run
quit: function(errorCode) {
console.info(`Run # ${runCount} completed with status:`, errorCode);
run();
},
};
}
// run the WASM code
function run() {
runCount++;
console.info(`Starting run #${runCount}`);
reportMemory();
setTimeout(() => {
factory(createModule());
}, RESTART_WAIT);
}
// print current memory usage
function reportMemory() {
let {rss, heapTotal, heapUsed, external, arrayBuffers} = process.memoryUsage();
let percentHeap = (heapUsed / heapTotal) * 100;
console.debug(`Heap Usage: ${b2s(heapUsed)} (${percentHeap.toFixed(1)}% of ${b2s(heapTotal)}) :: ArrayBuffers: ${b2s(arrayBuffers)} External: ${b2s(external)} [Total Memory (RSS): ${b2s(rss)}]`);
// # bytes to string
function b2s(b) {
let size = 0;
while (b > BYTES_PER_KB) {
b = b / BYTES_PER_KB;
size++;
}
switch (size) {
case 0: return `${b.toFixed(2)} B`;
case 1: return `${b.toFixed(2)} KB`;
case 2: return `${b.toFixed(2)} MB`;
case 3: return `${b.toFixed(2)} GB`;
case 4: return `${b.toFixed(2)} TB`;
default: return `${b.toFixed(2)} ??`;
}
}
}
run();
CC=emcc
CFLAGS =
CFLAGS += -Wall
CFLAGS += -Werror
CFLAGS += -s MODULARIZE
CFLAGS += -s EXIT_RUNTIME
all:
emcc leak.c $(CFLAGS) -o build/test.js
$ make && node leak.js
emcc leak.c -Wall -Werror -s MODULARIZE -s EXIT_RUNTIME -o build/test.js
Starting run #1
Heap Usage: 2.76 MB (52.5% of 5.26 MB) :: ArrayBuffers: 9.17 KB External: 1.04 MB [Total Memory (RSS): 19.52 MB]
this is a test
Run # 1 completed with status: 0
Starting run #2
Heap Usage: 3.35 MB (60.7% of 5.51 MB) :: ArrayBuffers: 30.03 KB External: 16.97 MB [Total Memory (RSS): 24.09 MB]
this is a test
Run # 2 completed with status: 0
Starting run #3
Heap Usage: 3.27 MB (39.6% of 8.26 MB) :: ArrayBuffers: 9.18 KB External: 32.95 MB [Total Memory (RSS): 28.20 MB]
this is a test
Run # 3 completed with status: 0
Starting run #4
Heap Usage: 3.38 MB (40.9% of 8.26 MB) :: ArrayBuffers: 30.05 KB External: 48.97 MB [Total Memory (RSS): 28.26 MB]
this is a test
Run # 4 completed with status: 0
Starting run #5
Heap Usage: 2.77 MB (33.5% of 8.26 MB) :: ArrayBuffers: 30.06 KB External: 64.97 MB [Total Memory (RSS): 28.73 MB]
this is a test
[...]
Starting run #101
Heap Usage: 7.15 MB (43.9% of 16.31 MB) :: ArrayBuffers: 30.81 KB External: 1.56 GB [Total Memory (RSS): 36.96 MB]
this is a test
Run # 101 completed with status: 0
Starting run #102
Heap Usage: 7.24 MB (44.4% of 16.31 MB) :: ArrayBuffers: 51.68 KB External: 1.58 GB [Total Memory (RSS): 37.00 MB]
this is a test
Run # 102 completed with status: 0
Starting run #103
Heap Usage: 7.23 MB (44.3% of 16.31 MB) :: ArrayBuffers: 9.96 KB External: 1.59 GB [Total Memory (RSS): 37.09 MB]
/Users/ampower/Projects/proto/emscripten-memory-leak/build/test.js:201
throw ex;
^
RangeError: WebAssembly.Memory(): could not allocate memory
at /Users/ampower/Projects/proto/emscripten-memory-leak/build/test.js:1414:18
at Timeout._onTimeout (/Users/ampower/Projects/proto/emscripten-memory-leak/leak.js:24:9)
at listOnTimeout (internal/timers.js:551:17)
at processTimers (internal/timers.js:494:7)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment