V8 memory leak? #17236
-
When I pass input array to a Deno Native Messaging host having length Not so long ago I was able to pass QuickJS, C, and C++ Native Messaging hosts can each process 200000 array input. Python exists when input is 175000. Is there a recent change to V8 which limits input to stadin and/or stdout; caches or buffers stdin or stdout? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 13 replies
-
@bartlomieju @ayame113 @lucacasonato @crowlKats @ry I'm pretty sure this is a bug in V8. Unless one of you can explain why V8 is writing When input to stdin is equal to or greater than 65536 memory usage exponentially increases to upwards of 700MB-1GB - this happens only when using Node.js or Deno JavaScript engines . Using the same code with QuickJS JavaScript engine, C and C++ Native Messaging hosts I get no such unexpected behaviour. I narrowed down the range when this happens and write what happens to a file.
is written to log.txt, which is expected
when I add 1 to that input array
is written to log.txt. The relevant Deno code
Node.js code
|
Beta Was this translation helpful? Give feedback.
-
It fails when receiving the second message because import { BufReader } from "https://deno.land/std@0.170.0/io/buf_reader.ts";
import { BufWriter } from "https://deno.land/std@0.170.0/io/buf_writer.ts";
const stdin = new BufReader(Deno.stdin);
const stdout = new BufWriter(Deno.stdout);
async function getMessage() {
const header = new Uint32Array(1);
await stdin.readFull(new Uint8Array(header.buffer));
const message = new Uint8Array(header[0]);
await stdin.readFull(message);
return message;
}
async function sendMessage(message) {
const header = new Uint32Array([message.length]);
await stdout.write(new Uint8Array(header.buffer));
await stdout.write(message);
await stdout.flush();
} I am not aware of any built-in equivalent in Node, but the following should work. function readFullSync(fd, buf) {
let offset = 0;
while (offset < buf.byteLength) {
offset += readSync(fd, buf, { offset });
}
return buf;
}
function getMessage() {
const header = new Uint32Array(1);
readFullSync(0, header);
const content = new Uint8Array(header[0]);
readFullSync(0, content);
return content;
} Original answerI cannot reproduce this locally. I installed the native messaging example and modified it as follows. When I visit // app/main.js
const port = chrome.runtime.connectNative("com.google.chrome.example.echo");
port.postMessage(new Array((4096 * 3) + 819));
// host/native-messaging-example-host
#!/usr/bin/env -S deno run --allow-write=log.txt
async function getMessage() {
const header = new Uint32Array(1);
await Deno.stdin.read(header);
await Deno.writeTextFile("log.txt", header[0]);
const output = new Uint8Array(header[0]);
await Deno.stdin.read(output);
return output;
}
await getMessage(); |
Beta Was this translation helpful? Give feedback.
It fails when receiving the second message because
Deno.stdin.read(buffer)
is not guaranteed to read exactlybuffer.byteLength
bytes, and thus the first message was not fully read.BufReader
from std provides a convenient way to ensure that the whole buffer is filled.