Skip to content

Conversation

@runk
Copy link
Owner

@runk runk commented Jan 22, 2025

Solves #885

Debugging script for reference

const fs = require('fs');
const crypto = require('crypto');

const showMemoryUsage = () => {
  const memoryUsage = process.memoryUsage();

  console.log(`X: ${Math.round(memoryUsage.heapUsed / 1024 / 1024)} MB`);
  console.log('Memory Usage:');
  console.log(
    `- RSS (Resident Set Size): ${Math.round(memoryUsage.rss / 1024 / 1024)} MB`
  );
  console.log(
    `- Heap Total: ${Math.round(memoryUsage.heapTotal / 1024 / 1024)} MB`
  );
  console.log(
    `- Heap Used: ${Math.round(memoryUsage.heapUsed / 1024 / 1024)} MB`
  );
  console.log(
    `- External: ${Math.round(memoryUsage.external / 1024 / 1024)} MB`
  );
  console.log(
    `- Array Buffers: ${Math.round(memoryUsage.arrayBuffers / 1024 / 1024)} MB`
  );
};

// const stream = fs.createWriteStream('./data');
// for (let i = 0; i < 1000; i++) {
//   stream.write(crypto.randomBytes(1024 * 1024));
// }
// stream.end();

const readFile2 = (filepath, cb) => {
  return new Promise((resolve, reject) => {
    const stat = fs.statSync(filepath);
    let buffer = Buffer.allocUnsafe(stat.size);
    let offset = 0;
    const stream = fs.createReadStream(filepath, {
      highWaterMark: 8 * 1024 * 1024,
    });

    stream.on('data', (chunk) => {
      chunk.copy(buffer, offset);
      offset += chunk.length;
    });

    stream.on('end', () => {
      stream.close();
      resolve(buffer);
    });

    stream.on('error', (err) => {
      reject(err);
    });
  });
};

const readFileOriginal = async (filepath) => {
  return fs.readFileSync(filepath);
};

const main = async () => {
  // showMemoryUsage();
  const now = performance.now();
  // const buffer = await readFileOriginal('./data');

  const buffer = await readFile2('./data');

  console.log('took', performance.now() - now);
  console.log(buffer.length);

  setTimeout(() => {
    showMemoryUsage();
  }, 2000);
};

main().catch(console.error);

@runk runk merged commit 0b31423 into master Jan 22, 2025
3 checks passed
@github-actions
Copy link

🎉 This PR is included in version 4.3.24 🎉

The release is available on:

Your semantic-release bot 📦🚀


const readFile = async (filepath: string): Promise<Buffer> => {
return new Promise((resolve, reject) => {
const chunks: Buffer[] = [];
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Old implementation used a list of buffers which was driving excessive memory usage + Buffer.concat which apparently is not memory friendly as well.

Now I'm allocating resulting buffer of the size of the file, and filling it with chunks as we go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants