gm icon indicating copy to clipboard operation
gm copied to clipboard

Possible Memory Leak?

Open robaca opened this issue 5 years ago • 5 comments

We are using the d3 module 1.23.1 to create thumbnails for images with code like the following:

this.gm(originalStream, 'someImage.jpg')
    .options({ timeout: 15000 })
    .autoOrient()
    .unsharp(0, 0.5)
    .resize(250, 500, '>')
    .stream('jpg', (err: Error, stdout: any) => {
        if (err) {
            return reject(err)
        }
        const someOutputStream = // create output stream
        stdout
            .pipe(someOutputStream)
            .on('finish', resolve)
            .on('error', reject)
    })

When calling this code multiple times, it seems that d3 stores some buffer references and we have get a memory leak. This is how a diff between two heapsnapshots looks like:

image

Do we have to do some cleanup to finally free resources?

robaca avatar Jul 22 '20 07:07 robaca

@robaca did you resolve this? We ran into the same thing.

hymair avatar Dec 16 '24 07:12 hymair

Hi @hymair we stopped using the module at that time in favor of directly spawning the executable.

robaca avatar Dec 16 '24 07:12 robaca

Thanks for the quick reply @robaca!

Do you keep the process running once spawned or you exit after each operation? Can you maybe share a code snippet?

hymair avatar Dec 16 '24 08:12 hymair

I was using this package to convert a pdf to an image. Here's what worked for me by spawning the executable directly:

import { spawn } from 'child_process'

/**
 * Converts a PDF buffer to a JPEG buffer with all pages concatenated vertically
 * @param pdfBuffer - The input PDF buffer
 * @returns Promise resolving to the JPEG buffer
 */
export async function pdfToImage(pdfBuffer: Buffer): Promise<Buffer> {
    return new Promise<Buffer>((resolve, reject) => {
        // Spawn convert process reading from stdin and writing to stdout
        const convert = spawn('convert', [
            '-density',
            '300',
            '-quality',
            '100',
            '-append',
            'pdf:-', // Read from stdin
            'jpeg:-', // Write to stdout
        ])

        const chunks: Buffer[] = []
        let errorOutput = ''

        // Collect output data
        convert.stdout.on('data', (chunk) => {
            chunks.push(Buffer.from(chunk))
        })

        // Collect error messages
        convert.stderr.on('data', (chunk) => {
            errorOutput += chunk.toString()
        })

        // Handle errors spawning the process
        convert.on('error', (error) => {
            reject(
                new Error(`Failed to spawn convert process: ${error.message}`),
            )
        })

        // Handle process completion
        convert.on('exit', (code) => {
            if (code !== 0) {
                reject(
                    new Error(
                        `Convert process failed with code ${code}: ${errorOutput}`,
                    ),
                )
                return
            }
            resolve(Buffer.concat(chunks))
        })

        // Write PDF data to stdin and close it
        convert.stdin.write(pdfBuffer)
        convert.stdin.end()
    })
}

hymair avatar Dec 16 '24 08:12 hymair

Can't tell much more as it's some time ago and I do not have access to that code any more. But if I remember correctly, we worked on files as we had some issues stdin/stdout in certain situations (like signed PDFs etc).

robaca avatar Dec 16 '24 08:12 robaca