nodejs スクリプトのメモリ リークを調査しています。
次のコード ブロックを検討してください (ソース コード全体は一番下にあります)。GetImage
バッファを割り当てる C 関数を呼び出し、それを解放するのは呼び出し元の責任です。行の後、GC中に解放されますかres.send(data)
?var dataPtr
app.get('/test', function(req, res)
{
res.contentType('image/jpeg');
var lengthPtr = ref.alloc('uint');
var dataPtr = ref.alloc('uchar*');
lib.GetImage(dataPtr, lengthPtr);
var length = lengthPtr.deref();
var data = ref.reinterpret(ref.deref(dataPtr), length);
res.send(data);
});
約 20000 件のリクエストを処理した後のエラー メッセージ:
Error: reinterpret: Cannot reinterpret from NULL pointer
at Object.reinterpret (/home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/ref/lib/ref.js:773:21)
at Object.handle (/home/ltse/LinuxPort/Experiments/NodeAddon/ffi.js:20:17)
at next_layer (/home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/router/route.js:103:13)
at Route.dispatch (/home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/router/route.js:107:5)
at /home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/router/index.js:213:24
at Function.proto.process_params (/home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/router/index.js:284:12)
at next (/home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/router/index.js:207:19)
at Layer.expressInit [as handle] (/home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/middleware/init.js:23:5)
at trim_prefix (/home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/router/index.js:255:15)
at /home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/router/index.js:216:9
...same error message repeated many times...
Error: reinterpret: Cannot reinterpret from NULL pointer
at Object.reinterpret (/home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/ref/lib/ref.js:773:21)
at Object.handle (/home/ltse/LinuxPort/Experiments/NodeAddon/ffi.js:20:17)
at next_layer (/home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/router/route.js:103:13)
at Route.dispatch (/home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/router/route.js:107:5)
at /home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/router/index.js:213:24
at Function.proto.process_params (/home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/router/index.js:284:12)
at next (/home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/router/index.js:207:19)
at Layer.expressInit [as handle] (/home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/middleware/init.js:23:5)
at trim_prefix (/home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/router/index.js:255:15)
at /home/ltse/LinuxPort/Experiments/NodeAddon/node_modules/express/lib/router/index.js:216:9
FATAL ERROR: Malloced operator new Allocation failed - process out of memory
NodeJS のソース コード:
var memwatch = require('memwatch');
var express = require('express');
var app = express();
var ref = require('ref');
var ffi = require('ffi');
var lib = ffi.Library('libsample',
{
'GetImage' : ['int', ['uchar **', 'uint *']]
});
app.get('/test', function(req, res)
{
res.contentType('image/jpeg');
var lengthPtr = ref.alloc('uint');
var dataPtr = ref.alloc('uchar*');
lib.GetImage(dataPtr, lengthPtr);
var length = lengthPtr.deref();
var data = ref.reinterpret(ref.deref(dataPtr), length);
res.send(data);
});
var server = app.listen(3000, function(){
console.log('Listening on port 3000.');
})
// memwatch
console.log('Monitoring memory usage...');
memwatch.on('leak', function(info){
console.log(info);
});
memwatch.on('stats', function(info){
console.log(info);
});
C 共有ライブラリのソース コード:
#include "sample.h"
#include <stdio.h>
#include <stdlib.h>
int GetImage(unsigned char** data, unsigned int * length)
{
FILE *fp;
unsigned int lSize;
unsigned char *buffer;
fp = fopen("***PATH TO JPG FILE***", "rb");
fseek( fp , 0L , SEEK_END);
lSize = ftell( fp );
rewind( fp );
buffer = calloc( 1, lSize+1 );
fread( buffer, lSize, 1, fp);
fclose(fp);
*data = buffer;
*length = lSize;
return 0;
}
共有ライブラリを構築するコマンド:
gcc -g -c -Wall -Werror -fpic sample.c
gcc -shared -g -o libsample.so sample.o
Apache ベンチマーク ツールを使用して、プログラムをクラッシュさせました。
ab -n 120000 -c 4 http://localhost:3000/test