https://github.com/XadillaX/thmclrx/tree/fb1fc3e69c8fa7dac7037ba86e923ce0c8da9ab1/src
这个就是我写的 Addon,以及在
https://github.com/XadillaX/thmclrx/blob/fb1fc3e69c8fa7dac7037ba86e923ce0c8da9ab1/test/test.js
是测试代码。
我指的慢不是执行的时候慢,而是“善后”,我也不知道怎么解释——
总之效果就是 console
已经有东西打印出来了,但是要过好一段时间之后才能开始下一步操作。
比如把
for(var i = 0; i < 35500; i++) {
rgb.push({
r : Number.random(0, 255),
g : Number.random(0, 255),
b : Number.random(0, 255)
});
}
里面的 35500 改成一个很小的数字,那么处理完 console
出来之后秒退,但是如果改成更大的话,console
之后要等非常就之后程序才结束。
照理说都已经 console
出来了,说明由 C++ 处理的那段程序段已经结束了,但是为什么还是要等那么久呢?
在线等!急!
因为gc时间到了,js主线程必须卡住 :D
@wenbob 确定是这个原因吗 0. 0 所以说在 C++ 里面的闭包中 scope 里面产生的东西都要被回收,要回收的东西太多了然后卡住了吗?
@wenbob 通常 GC 的话应该只是回收 Handle<...>
或者 Local<...>
之类的东西吧?我的代码里面没有什么比较大的东西是这两种类型的,基本上是由我自己去处理生命周期的,为什么会卡呢?
你改用Buffer传参数,全部测完再释放,就知道区别了
实际上node.js程序只要遇到大数组、大JSON的计算,都会很卡,没有例外的。计算方面的事情,我就不建议把数据保存在js这一侧。如果全部是在native代码里存储和计算,情况会好得多。需要数据的时候,再包装成js对象返给js线程就行了,一次不要返太多数据,免得序列化的时候又卡住了
@wenbob 问题是我用纯 js 来写没这么卡啊。
我计算的时候是传进去逐像素信息,计算出来的是主题色信息。
var rgb = [];
for(var i = 0; i < 35500; i++) {
rgb.push({
r : Number.random(0, 255),
g : Number.random(0, 255),
b : Number.random(0, 255)
});
}
var result = thmclrx.cpp.mindifferGet(rgb);
console.log(result);
result = thmclrx.cpp.mindifferGet(rgb);
上面的测试代码,照理说 rgb
在第一次计算完之后不会被 GC 吧?但是上面的测试代码还是会再第一次处理完之后 console.log
出来之后卡很久才开始第二次计算。
@xadillax 在js与native交互的时候, native 那一侧也产生了大量的gc,这就是问题了。
@wenbob Buffer 不会有这个问题吗?
传rgb数组到native的时候,会再复制一次这个超大的数组,你说怎么不会有gc
我认为Buffer不会,如果这个也要复制内存块的话,那就太对不起这个名字了。没测过,我之前遇到这类问题后,就果断把数据结构全部在Addon里实现了,js这边并不拥有任何大数组什么的
@wenbob 现在的问题是这样的——我能通过 node.js 很方便地获取各种不同类型图片的像素信息,而且有些图片是在线获取的。总不能说连着 HTTP 请求也交给 C++ 吧,如果是这样我直接用 C++ 写不用 node 了。
另一个处理方式是使用stream之类的机制来做大量数据的传递。无论如何,不要把一个很大的对象传给 C++ addon,大对象必然会卡住js线程。
@wenbob 好吧,我再想想别的办法看。
@xadillax 用stream吧
感觉还是不对啊,我做了个实验:
C++ 文件
#include <v8.h>
#include <node.h>
using namespace v8;
Handle<Value> Test1(const Arguments& args)
{
HandleScope scope;
Local<Value> arg = args[0];
Local<Array> arr = Local<Array>::Cast(arg);
return scope.Close(arr);
}
void Init(Handle<Object> exports)
{
exports->Set(String::NewSymbol("test1"),
FunctionTemplate::New(Test1)->GetFunction());
}
NODE_MODULE(test, Init);
Node 文件
var tester = require("./build/Release/test.node");
var object1 = [];
var object2;
for(var i = 0; i < 1000000; i++) {
object1.push({
r: i,
g: i,
b: i
});
}
console.log(tester.test1(object1)[0]);
console.log(tester.test1(object1)[0]);
这里的两次调用 tester.test1
几乎无间隔,而且跑完马上就退出了,没有很明显的所谓 GC 的感觉。
不知何解?
@wenbob 我做了个实验在下面一楼,好像不是这里的问题啊?
好吧问题我自己找到了。
在 C++
层面上写内存池为了贪省力直接用了 stl
。用什么不好,而且我还用了 list
,然后就卡住了。
现在还是贪省力,不过改用了 queue
然后就解决了。