首先,我承认我是 c ++ 插件的新手 node.js 。
我正在写我的第一个插件,并且我得到了一个好结果:插件做了我想要的。我从互联网上发现的各种例子中复制了两种语言之间的复杂数据,但我对所写内容几乎一无所知。
让我害怕的第一件事是我没有写任何东西似乎释放了一些记忆;令我严重担心的另一件事是,我不知道我写的内容是否会对 V8 垃圾收集器造成帮助或造成混淆;顺便说一句,我不知道是否有更好的方法来做我做的事情(在 C ++ 中迭代 js对象 键,在 C ++ 中创建 js Object ,在 C ++ 中创建字符串以用作属性 of js Object s以及我在代码中可以找到的其他错误。)
所以,在继续写我的插件的真实数学工作之前,我想与社区分享 nan 和 V8 部分来询问如果你看到错误或者可以更好地完成。
谢谢大家的帮助,
ICC
#include <map>
#include <nan.h>
using v8::Array;
using v8::Function;
using v8::FunctionTemplate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::Value;
using v8::String;
using Nan::AsyncQueueWorker;
using Nan::AsyncWorker;
using Nan::Callback;
using Nan::GetFunction;
using Nan::HandleScope;
using Nan::New;
using Nan::Null;
using Nan::Set;
using Nan::To;
using namespace std;
class Data {
public:
int dt1;
int dt2;
int dt3;
int dt4;
};
class Result {
public:
int x1;
int x2;
};
class Stats {
public:
int stat1;
int stat2;
};
typedef map<int, Data> DataSet;
typedef map<int, DataSet> DataMap;
typedef map<float, Result> ResultSet;
typedef map<int, ResultSet> ResultMap;
class MyAddOn: public AsyncWorker {
private:
DataMap *datas;
ResultMap results;
Stats stats;
public:
MyAddOn(Callback *callback, DataMap *set): AsyncWorker(callback), datas(set) {}
~MyAddOn() { delete datas; }
void Execute () {
for(DataMap::iterator i = datas->begin(); i != datas->end(); ++i) {
int res = i->first;
DataSet *datas = &i->second;
for(DataSet::iterator l = datas->begin(); l != datas->end(); ++l) {
int dt4 = l->first;
Data *data = &l->second;
// TODO: real population of stats and result
}
// test result population
results[res][res].x1 = res;
results[res][res].x2 = res;
}
// test stats population
stats.stat1 = 23;
stats.stat2 = 42;
}
void HandleOKCallback () {
Local<Object> obj;
Local<Object> res = New<Object>();
Local<Array> rslt = New<Array>();
Local<Object> sts = New<Object>();
Local<String> x1K = New<String>("x1").ToLocalChecked();
Local<String> x2K = New<String>("x2").ToLocalChecked();
uint32_t idx = 0;
for(ResultMap::iterator i = results.begin(); i != results.end(); ++i) {
ResultSet *set = &i->second;
for(ResultSet::iterator l = set->begin(); l != set->end(); ++l) {
Result *result = &l->second;
// is it ok to declare obj just once outside the cycles?
obj = New<Object>();
// is it ok to use same x1K and x2K instances for all objects?
Set(obj, x1K, New<Number>(result->x1));
Set(obj, x2K, New<Number>(result->x2));
Set(rslt, idx++, obj);
}
}
Set(sts, New<String>("stat1").ToLocalChecked(), New<Number>(stats.stat1));
Set(sts, New<String>("stat2").ToLocalChecked(), New<Number>(stats.stat2));
Set(res, New<String>("result").ToLocalChecked(), rslt);
Set(res, New<String>("stats" ).ToLocalChecked(), sts);
Local<Value> argv[] = { Null(), res };
callback->Call(2, argv);
}
};
NAN_METHOD(AddOn) {
Local<Object> datas = info[0].As<Object>();
Callback *callback = new Callback(info[1].As<Function>());
Local<Array> props = datas->GetOwnPropertyNames();
Local<String> dt1K = Nan::New("dt1").ToLocalChecked();
Local<String> dt2K = Nan::New("dt2").ToLocalChecked();
Local<String> dt3K = Nan::New("dt3").ToLocalChecked();
Local<Array> props2;
Local<Value> key;
Local<Object> value;
Local<Object> data;
DataMap *set = new DataMap();
int res;
int dt4;
DataSet *dts;
Data *dt;
for(uint32_t i = 0; i < props->Length(); i++) {
// is it ok to declare key, value, props2 and res just once outside the cycle?
key = props->Get(i);
value = datas->Get(key)->ToObject();
props2 = value->GetOwnPropertyNames();
res = To<int>(key).FromJust();
dts = &((*set)[res]);
for(uint32_t l = 0; l < props2->Length(); l++) {
// is it ok to declare key, data and dt4 just once outside the cycles?
key = props2->Get(l);
data = value->Get(key)->ToObject();
dt4 = To<int>(key).FromJust();
dt = &((*dts)[dt4]);
int dt1 = To<int>(data->Get(dt1K)).FromJust();
int dt2 = To<int>(data->Get(dt2K)).FromJust();
int dt3 = To<int>(data->Get(dt3K)).FromJust();
dt->dt1 = dt1;
dt->dt2 = dt2;
dt->dt3 = dt3;
dt->dt4 = dt4;
}
}
AsyncQueueWorker(new MyAddOn(callback, set));
}
NAN_MODULE_INIT(Init) {
Set(target, New<String>("myaddon").ToLocalChecked(), GetFunction(New<FunctionTemplate>(AddOn)).ToLocalChecked());
}
NODE_MODULE(myaddon, Init)
一年半之后......
如果有人感兴趣,我的服务器已启动并运行,因为我的问题及其所需的内存量是稳定的。
我不能说我写的代码是否真的没有内存泄漏,或者在每个线程执行结束时是否释放了丢失的内存,但是如果你像我一样害怕,我可以说使用相同的结构并且电话不会引起任何实际问题。
答案 0 :(得分:0)
你实际上使用代码行释放了一些你使用的内存:
~MyAddOn() { delete datas; }
从本质上讲,C ++内存管理归结为始终为delete
创建的每个对象调用new
。还有许多其他特定于体系结构和传统的“C”内存管理功能,但是当您不需要性能优势时,并不一定要使用这些功能。
作为可能存在内存泄漏的示例:您将*callback
指针中保存的对象传递给函数AsyncQueueWorker
。但是在你的代码中没有任何地方释放这个指针,所以除非Queue worker为你释放它,否则这里会有内存泄漏。
您可以使用valgrind等内存工具进一步测试您的程序。它会为您发现大多数内存问题,强烈建议。
我观察到的一件事是你经常问(转述):
在我的循环之外声明X是否可以?
答案实际上是在你的循环中声明变量 更好,只要你能做到。尽可能将变量声明为内部,除非您必须重复使用它们。变量在范围中被限制在最外面的{}
括号中。您可以在this question中详细了解相关信息。
可以为所有对象使用相同的x1K和x2K实例吗?
本质上,当你这样做时,如果其中一个对象修改了它的'x1K'字符串,那么它将为所有这些字符串改变。优点是你可以释放内存。如果所有这些对象的字符串都是相同的,而不是必须存储1,000,000个拷贝,那么你的计算机只会在内存中保留一个,而是拥有1,000,000个指针。如果字符串在amd64
下长度为9个ASCII字符,那么这相当于节省了大量内存。
顺便说一下,如果你不打算在声明之后修改变量,你可以将它声明为const
,这是一个常量的关键字,它强制编译器在你之后检查你的变量是否被修改宣言。你可能不得不处理很多关于只接受他们不修改的非const版本的函数的编译器错误,其中一些可能不是你自己的代码,在这种情况下你运气不好。尽可能保守非常量变量可以帮助发现问题。