Rust で Node.js 拡張機能を作成しています。このおもちゃのライブラリを C から呼び出して、Valgrind でチェックしたところ、メモリ リークは見つかりませんでした。
Python と Ruby から同じライブラリを呼び出し、無限ループで実行しましたが、メモリ リークの兆候は見られません。(ここでの評判が悪いため、写真を投稿できません)。
同じライブラリが Node.js から呼び出されると、時間の経過とともにメモリ使用量が増加するようです。
時間の単位はループの周期であり、リアルタイムではありません。
Rustコードは次のとおりです。
#[repr(C)]
pub struct Matrix {
m: Vec<Vec<f64>>,
}
#[no_mangle]
pub extern "C" fn matrix_new(nrow: usize, ncol: usize) -> *mut Matrix {
let mut m = Vec::new();
for _ in 0..(nrow) {
let mut n = Vec::new();
for _ in 0..(ncol) {
n.push(0.0);
}
m.push(n);
}
Box::into_raw(Box::new(Matrix { m: m }))
}
#[no_mangle]
pub extern "C" fn matrix_free(matrix: *mut Matrix) {
if matrix.is_null() {
return
}
unsafe { Box::from_raw(matrix); }
}
元の Node.js コードは次のとおりです。
var ref = require('ref');
var ffi = require('ffi');
var c_matrix = ref.types.void;
var c_matrix_ptr = ref.refType(c_matrix);
var libmatrix = ffi.Library('./target/release/libmatrix.so', {
'matrix_new': [ c_matrix_ptr, ['size_t', 'size_t']],
'matrix_get': [ 'double', [ c_matrix_ptr, 'size_t', 'size_t']],
'matrix_set': [ 'double', [ c_matrix_ptr, 'size_t', 'size_t', 'double']],
'matrix_free': [ 'void', [ c_matrix_ptr ]]
});
var matrix = function(nrow, ncol) {
"use strict";
var matrix = libmatrix.matrix_new(nrow, ncol);
Object.defineProperty(this, '_matrix', {
value: matrix,
writeable: false
});
return this;
};
matrix.prototype.get = function(row, col) {
"use strict";
return libmatrix.matrix_get(this._matrix, row, col);
};
matrix.prototype.set = function(row, col, value) {
"use strict";
libmatrix.matrix_set(this._matrix, row, col, value);
};
matrix.prototype.free = function() {
"use strict";
libmatrix.matrix_free(this._matrix);
};
module.exports = matrix;
if (!module.parent) {
while (true) {
var m = new matrix(3, 3);
m.free();
m = null;
delete global.m;
global.gc();
console.log(process.memoryUsage().rss);
}
}
いくつかの情報:
- OS: Debian GNU/Linux (ジェシー)
- Node.js: 7.2.0
- ノード-gyp: 7.2.0
- ffi: 2.2.0
- 参照:1.3.3
- さび: 1.13.0
同じライブラリを C で書き直しました。
typedef struct Matrix {
size_t nrow;
size_t ncol;
double** mtx;
} Matrix;
void* matrix_new(size_t row, size_t col) {
Matrix* m = malloc(sizeof(Matrix));
m->nrow = row;
m->ncol = col;
m->mtx = malloc(m->nrow * sizeof(double*));
for (int i = 0; i < m->nrow; i++) {
*((m->mtx)+i) = (double*) malloc(m->ncol * sizeof(double));
}
for (int i = 0; i < m->nrow; i++) {
for (int j = 0; j < m->ncol; j++) {
m->mtx[i][j] = 0.0;
}
}
return (void*) m;
}
void matrix_free(void* m) {
if (m == NULL) {
return;
}
double** ptr = ((Matrix*) m)->mtx;
for (int i = 0; i < ((Matrix*) m)->nrow; i++) {
free((void*) (ptr[i]));
}
free((void*) ((Matrix*) m)->mtx);
free((void*) m);
}
また、Node のバージョンを 7.2.0 から 7.3.0 に変更しました。C と Rust の両方を実装した Node.js モジュールのメモリ使用量は次のとおりです。
Node.js コードを変更せずに no-op ライブラリを試してみたところ、驚くべきことがわかりました。