sqlanywhere / node-sqlanywhere

SAP SQL Anywhere Database Client for Node
Apache License 2.0
39 stars 36 forks source link

Memory leak(?) in Version 1.0.24 #32

Open viktor-ch opened 5 years ago

viktor-ch commented 5 years ago

It seems to be a memory leak in the latest version when calling .exec() within a promise.

I tested two last versions (1.0.23 and 1.0.24) with node 10.14.2 using the test code below. The standard callback approach works just fine in both versions. But when using promises I observed significant heap usage growth in version 1.0.24.

Thank you very much in advance, Viktor

Test results:

v.1.0.23: Callbacks: Start : heapTotal = 6.23 MB, heapUsed = 3.73 MB Finish: heapTotal = 40.23 MB, heapUsed = 9.94 MB Promises: Start : heapTotal = 6.23 MB, heapUsed = 3.73 MB Finish: heapTotal = 43.23 MB, heapUsed = 19.33 MB

v.1.0.24: Callbacks: Start : heapTotal = 6.23 MB, heapUsed = 3.73 MB Finish: heapTotal = 43.23 MB, heapUsed = 9.95 MB Promises: Start : heapTotal = 6.23 MB, heapUsed = 3.73 MB Finish: heapTotal = 617.23 MB, heapUsed = 578.01 MB

Test :

const conn = require('sqlanywhere').createConnection();

const dbParams = {
    // Server  : 'xxxxx',
    UserId  : 'DBA',
    Password: 'sql',
  };
const select = "SELECT row_num, 'test long long string' || row_num as str FROM sa_rowgenerator( 1, 50000 );"

//----------------------------------------------------------------------
// execute the select 'count' times using the standard callback approach 
function testCallback(count) {
    const exec = function() {
        conn.exec(select, (err, result) => {
            if(err) {
                console.log(err);
            }
            else {
                console.log(`Iteration: ${count} Rows: ${result.length}`);
                if(--count > 0) {
                    setTimeout(exec, 0)
                }
                else {
                    conn.disconnect(err => logMemoryUsage(usedStart, process.memoryUsage()));
                }
            }
        })
    }
    conn.connect(dbParams, err => err ? console.log(err) :  exec());
 }

//----------------------------------------------------------------------
// execute the select 'count' times using Promises 
async function testPromise(count) {
    const connect = async function() {
        return new Promise( (resolve, reject) => {
            conn.connect(dbParams, err => err ? reject(err) : resolve());
        });
    }
    const disconnect = async function() {
        return new Promise( (resolve, reject) => {
            conn.disconnect(err => err ? reject(err) : resolve());
        });
    }
    const exec = async function() {
        return new Promise( (resolve, reject) => {
            conn.exec(select, (err, result) => err ? reject(err) : resolve(result));
        });
    }
    try {
        await connect();
        for(let i = count; i > 0; --i) {
            const result = await exec();
            console.log(`Iteration: ${i} Rows: ${result.length}`);
        }
        await disconnect();
        logMemoryUsage(usedStart, process.memoryUsage());
    }
    catch(err) {
        console.log(err);
    }
 }

//----------------------------------------------------------------------
const usedStart = process.memoryUsage();
function logMemoryUsage(startMemory, finishMemory) {
    const toMB = mem => Math.round(mem / 1024 / 1024 * 100) / 100; 
    console.log(`Start : heapTotal = ${toMB(startMemory.heapTotal) } MB, heapUsed = ${toMB(startMemory.heapUsed) } MB`);
    console.log(`Finish: heapTotal = ${toMB(finishMemory.heapTotal)} MB, heapUsed = ${toMB(finishMemory.heapUsed)} MB`);
}

//----------------------------------------------------------------------
// enable one of the following functions:
//----------------------------------------------------------------------
// testCallback(100);
testPromise(100);
steveostop commented 2 years ago

I can confirm having memory leak issues as well using the most recent version. I have a simple ExpressJS API setup to retrieve data for an internal webapp.

Using async/await the app quickly grows in memory usage crashes.

Just now refactored to not use async/await and the app's heap usage never gets close in comparison.

Megapixel99 commented 10 months ago

Has this been fixed?