每 15 秒查询一次 DB2,导致 NodeJS 内存泄漏
Querying DB2 every 15 seconds causing memory leak in NodeJS
我有一个应用程序,它使用 IBM 的 idb-connector 在 iSeries 上每 15 秒检查一次 DB2 中的新条目。我有一个异步函数,它 return 查询到 socket.io 的结果,它发出一个包含前端数据的事件。我已经将内存泄漏缩小到异步函数。我已经阅读了多篇关于常见内存泄漏原因以及如何诊断它们的文章。
Rising Stack: garbage collection explained
Marmelab: Finding And Fixing Node.js Memory Leaks: A Practical Guide
但我还是没看出问题出在哪里。此外,我无法获得在系统上安装 node-gyp 的权限,这意味着大多数内存管理工具都无法使用,因为 memwatch、heapdump 等需要安装 node-gyp。这是功能基本结构的示例。
const { dbconn, dbstmt } = require('idb-connector');// require idb-connector
async function queryDB() {
const sSql = `SELECT * FROM LIBNAME.TABLE LIMIT 500`;
// create new promise
let promise = new Promise ( function(resolve, reject) {
// create new connection
const connection = new dbconn();
connection.conn("*LOCAL");
const statement = new dbstmt(connection);
statement.exec(sSql, (rows, err) => {
if (err) {
throw err;
}
let ticks = rows;
statement.close();
connection.disconn();
connection.close();
resolve(ticks.length);// resolve promise with varying data
})
});
let result = await promise;// await promise
return result;
};
async function getNewData() {
const data = await queryDB();// get new data
io.emit('newData', data)// push to front end
setTimeout(getNewData, 2000);// check again in 2 seconds
};
关于泄漏点有什么想法吗?我使用 async/await 不正确吗?或者我 creating/destroying 数据库连接不正确?如果您能帮助找出此代码泄漏的原因,我们将不胜感激!!
编辑:忘记提及我对后端流程的控制有限,因为它们由另一个团队处理。我只是检索他们填充数据库的数据并将其添加到网页中。
编辑 2:我想我已经将问题缩小到没有正确清理数据库连接。但是,据我所知,我已经按照他们 github repo 上建议的说明进行操作。
我不知道您具体问题的答案,但我不会每 15 秒发出一次查询,我可能会以不同的方式解决这个问题。原因是当环境可以告诉我事件发生时,我通常不喜欢钓鱼探险。
因此,在这种情况下,您可能想尝试一个数据库触发器,该触发器在添加时将行的键加载到数据队列中,甚至在必要时更改或删除。然后,您只需进行异步调用即可等待数据队列中的记录。这是更实时的,事件处理程序仅在记录出现时调用。处理程序可以从数据库中获取特定记录,因为您知道它是关键。数据队列比数据库 IO 快得多,触发器的开销很小。
我发现这种方法有几个潜在的优势:
- 您不会发出许多可能会或可能不会 return 数据的查询。
- 事件会在记录添加到 table 时触发,而不是 15 秒后触发。
- 您不必为一条或多条新记录的可能性编码,它始终为 1,即数据队列中提到的一条。
首先要注意的是,如果出现错误,可能会打开数据库连接。
if (err) {
throw err;
}
同样在成功的情况下 connection.disconn();
和 connection.close();
return 布尔值表明操作成功 (according to documentation)
总是可能的情况是在第 3 方库中堆积连接对象。
我会检查那些。
是的,您必须关闭连接。
不要制作常量数据。默认情况下您不需要承诺 statement.exec 是异步的并通过 return 结果处理它;
keep setTimeout(getNewData, 2000);// 2 秒后再次检查
在 getNewData 之外的行,否则它会变成递归无限循环。
示例代码
const {dbconn, dbstmt} = require('idb-connector');
const sql = 'SELECT * FROM QIWS.QCUSTCDT';
const connection = new dbconn(); // Create a connection object.
connection.conn('*LOCAL'); // Connect to a database.
const statement = new dbstmt(dbconn); // Create a statement object of the connection.
statement.exec(sql, (result, error) => {
if (error) {
throw error;
}
console.log(`Result Set: ${JSON.stringify(result)}`);
statement.close(); // Clean up the statement object.
connection.disconn(); // Disconnect from the database.
connection.close(); // Clean up the connection object.
return 结果;
});
*async function getNewData() {
const data = await queryDB();// get new data
io.emit('newData', data)// push to front end
setTimeout(getNewData, 2000);// check again in 2 seconds
};*
change to
**async function getNewData() {
const data = await queryDB();// get new data
io.emit('newData', data)// push to front end
};
setTimeout(getNewData, 2000);// check again in 2 seconds**
已确认这是我使用的 idb-connector 库中的内存泄漏。 Link 至 github 问题 Here. Basically there was a C++ array that never had it's memory deallocated. A new version was added and the commit can viewed Here。
我有一个应用程序,它使用 IBM 的 idb-connector 在 iSeries 上每 15 秒检查一次 DB2 中的新条目。我有一个异步函数,它 return 查询到 socket.io 的结果,它发出一个包含前端数据的事件。我已经将内存泄漏缩小到异步函数。我已经阅读了多篇关于常见内存泄漏原因以及如何诊断它们的文章。
Rising Stack: garbage collection explained
Marmelab: Finding And Fixing Node.js Memory Leaks: A Practical Guide
但我还是没看出问题出在哪里。此外,我无法获得在系统上安装 node-gyp 的权限,这意味着大多数内存管理工具都无法使用,因为 memwatch、heapdump 等需要安装 node-gyp。这是功能基本结构的示例。
const { dbconn, dbstmt } = require('idb-connector');// require idb-connector
async function queryDB() {
const sSql = `SELECT * FROM LIBNAME.TABLE LIMIT 500`;
// create new promise
let promise = new Promise ( function(resolve, reject) {
// create new connection
const connection = new dbconn();
connection.conn("*LOCAL");
const statement = new dbstmt(connection);
statement.exec(sSql, (rows, err) => {
if (err) {
throw err;
}
let ticks = rows;
statement.close();
connection.disconn();
connection.close();
resolve(ticks.length);// resolve promise with varying data
})
});
let result = await promise;// await promise
return result;
};
async function getNewData() {
const data = await queryDB();// get new data
io.emit('newData', data)// push to front end
setTimeout(getNewData, 2000);// check again in 2 seconds
};
关于泄漏点有什么想法吗?我使用 async/await 不正确吗?或者我 creating/destroying 数据库连接不正确?如果您能帮助找出此代码泄漏的原因,我们将不胜感激!!
编辑:忘记提及我对后端流程的控制有限,因为它们由另一个团队处理。我只是检索他们填充数据库的数据并将其添加到网页中。
编辑 2:我想我已经将问题缩小到没有正确清理数据库连接。但是,据我所知,我已经按照他们 github repo 上建议的说明进行操作。
我不知道您具体问题的答案,但我不会每 15 秒发出一次查询,我可能会以不同的方式解决这个问题。原因是当环境可以告诉我事件发生时,我通常不喜欢钓鱼探险。
因此,在这种情况下,您可能想尝试一个数据库触发器,该触发器在添加时将行的键加载到数据队列中,甚至在必要时更改或删除。然后,您只需进行异步调用即可等待数据队列中的记录。这是更实时的,事件处理程序仅在记录出现时调用。处理程序可以从数据库中获取特定记录,因为您知道它是关键。数据队列比数据库 IO 快得多,触发器的开销很小。
我发现这种方法有几个潜在的优势:
- 您不会发出许多可能会或可能不会 return 数据的查询。
- 事件会在记录添加到 table 时触发,而不是 15 秒后触发。
- 您不必为一条或多条新记录的可能性编码,它始终为 1,即数据队列中提到的一条。
首先要注意的是,如果出现错误,可能会打开数据库连接。
if (err) {
throw err;
}
同样在成功的情况下 connection.disconn();
和 connection.close();
return 布尔值表明操作成功 (according to documentation)
总是可能的情况是在第 3 方库中堆积连接对象。
我会检查那些。
是的,您必须关闭连接。 不要制作常量数据。默认情况下您不需要承诺 statement.exec 是异步的并通过 return 结果处理它; keep setTimeout(getNewData, 2000);// 2 秒后再次检查 在 getNewData 之外的行,否则它会变成递归无限循环。 示例代码
const {dbconn, dbstmt} = require('idb-connector');
const sql = 'SELECT * FROM QIWS.QCUSTCDT';
const connection = new dbconn(); // Create a connection object.
connection.conn('*LOCAL'); // Connect to a database.
const statement = new dbstmt(dbconn); // Create a statement object of the connection.
statement.exec(sql, (result, error) => {
if (error) {
throw error;
}
console.log(`Result Set: ${JSON.stringify(result)}`);
statement.close(); // Clean up the statement object.
connection.disconn(); // Disconnect from the database.
connection.close(); // Clean up the connection object.
return 结果; });
*async function getNewData() {
const data = await queryDB();// get new data
io.emit('newData', data)// push to front end
setTimeout(getNewData, 2000);// check again in 2 seconds
};*
change to
**async function getNewData() {
const data = await queryDB();// get new data
io.emit('newData', data)// push to front end
};
setTimeout(getNewData, 2000);// check again in 2 seconds**
已确认这是我使用的 idb-connector 库中的内存泄漏。 Link 至 github 问题 Here. Basically there was a C++ array that never had it's memory deallocated. A new version was added and the commit can viewed Here。