1.Persistent.Reset并非引用

v8源码:

V8_INLINE Persistent() : PersistentBase<T>(nullptr) {}template <class T>
void PersistentBase<T>::Reset() {if (this->IsEmpty()) return;V8::DisposeGlobal(reinterpret_cast<internal::Address*>(this->val_));val_ = nullptr;
}template <class T>
template <class S>
void PersistentBase<T>::Reset(Isolate* isolate, const Local<S>& other) {static_assert(std::is_base_of<T, S>::value, "type check");Reset();if (other.IsEmpty()) return;this->val_ = New(isolate, other.val_);
}template <class T>
template <class S>
void PersistentBase<T>::Reset(Isolate* isolate,const PersistentBase<S>& other) {static_assert(std::is_base_of<T, S>::value, "type check");Reset();if (other.IsEmpty()) return;this->val_ = New(isolate, other.val_);
}

所以如果代码中使用了NewPersistent.Reset(OldPersistent),要调用OldPersistent.Reset()释放掉。

2.NewInstance会导致残留Constructor,创建一个会生成两个,释放只能释放一个。

Nan::HandleScope scope;// Prepare constructor templateLocal<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);tpl->SetClassName(Nan::New(ClassName).ToLocalChecked());tpl->InstanceTemplate()->SetInternalFieldCount(1);Nan::SetPrototypeMethod(...);Local<Function> cons = tpl->GetFunction();return Nan::NewInstance(cons).ToLocalChecked();

ps:使用heapdump库 kill -USR2 [进程号]产生的heapdump文件,第三个constructor本应与第一个对应,是100个,结果却是200个,且程序中执行清理工作时,只能释放掉100个。也就是每次NewInstance会先生成一份数据,内个我们不可控,本应作为Local类型的在作用域结束后应该释放,但并没有。之后我们通过GetReturnValue().Set(js);打进v8里是深拷贝的操作,于是形成了两个,释放也只能释放掉后面v8里的。

之前是使用了Nan库,发现新旧版本有差距

nan_maybe_43_inl.h:
inline
MaybeLocal<v8::Object> NewInstance(v8::Local<v8::Function> h, int argc, v8::Local<v8::Value> argv[]) {v8::Isolate *isolate = v8::Isolate::GetCurrent();v8::EscapableHandleScope scope(isolate);return scope.Escape(h->NewInstance(isolate->GetCurrentContext(), argc, argv).FromMaybe(v8::Local<v8::Object>()));
}nan_maybe_pre_43_inl.h:
inline
MaybeLocal<v8::Object> NewInstance(v8::Local<v8::Function> h, int argc, v8::Local<v8::Value> argv[]) {return MaybeLocal<v8::Object>(h->NewInstance(argc, argv));
}

其中Escape 方法复制参数中的值至一个封闭的域中,然后删除其他本地句柄,最后返回这个可以被安全返回的新句柄副本。

http://www.360doc.com/content/16/0701/22/832545_572287892.shtml

在这个模型下,有一个非常常见的陷阱需要注意:你不可以直接地在一个声明了句柄域的函数中返回一个本地句柄。如果你这么做了,那么你试图返回的本地句柄,将会在函数返回之前,在句柄域的析构函数中被删除。正确的做法是使用 EscapableHandleScope 来代替 HandleScope 创建句柄域,然后调用 Escape 方法,并且传入你想要返回的句柄。

怀疑是这个操作导致的,也包括Nan库是否就是有一些问题,于是决定废弃Nan库

先尝试  cons->NewInstance(isolate->GetCurrentContext(),3,argv).ToLocalChecked();依然无效,怀疑是不是Nan的new方法构造构造FunctionTemplate出的问题。

Local<FunctionTemplate> tpg = Nan::New<FunctionTemplate>(New);

在此基础上,把FunctionTemplate改成原生方法

Local<FunctionTemplate> tpg = Nan::New<FunctionTemplate>(New); -->Local<FunctionTemplate> tpg = FunctionTemplate::New(isolate);

会提前销毁,导致使用时非法指针,可见作用域还是不一样。

重写了generateJSInstance,取消Nan库所有方法的使用,都用v8原生方法实现

 //Nan::HandleScope scope;Isolate *isolate = Isolate::GetCurrent();v8::EscapableHandleScope Escope(isolate);HandleScope scope(isolate);Local<FunctionTemplate> tpg = FunctionTemplate::New(isolate);Local<String> v8name=String::NewFromUtf8(isolate, ClassName.c_str(), NewStringType::kInternalized).ToLocalChecked();tpg->SetClassName(v8name);tpg->InstanceTemplate()->SetInternalFieldCount(1);Local<Function> cons = tpg->GetFunction();Local<v8::Value> argv[3] = {..., ..., ...};Local<Object> js;//js = cons->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();//Escope.Escape没有效果//js = Escope.Escape(cons->NewInstance(isolate->GetCurrentContext(),3,argv).FromMaybe(v8::Local<v8::Object>()));js = cons->NewInstance(isolate->GetCurrentContext(),3,argv).ToLocalChecked();//置成SideEffectType::kHasNoSideEffect没有效果//js = cons->NewInstanceWithSideEffectType(isolate->GetCurrentContext(),3,argv,SideEffectType::kHasNoSideEffect).ToLocalChecked();args.GetReturnValue().Set(js);constructor.Reset();return ;

结果依然无效。

所以结论是还是v8原生NewInstance引发的问题 。

NewInstance会调用NewInstanceWithSideEffectType

NewInstanceWithSideEffectType源码

MaybeLocal<Object> Function::NewInstanceWithSideEffectType(Local<Context> context, int argc, v8::Local<v8::Value> argv[],SideEffectType side_effect_type) const {auto isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.Execute");ENTER_V8(isolate, context, Function, NewInstance, MaybeLocal<Object>(),InternalEscapableScope);i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate);auto self = Utils::OpenHandle(this);STATIC_ASSERT(sizeof(v8::Local<v8::Value>) == sizeof(i::Handle<i::Object>));bool should_set_has_no_side_effect =side_effect_type == SideEffectType::kHasNoSideEffect &&isolate->debug_execution_mode() == i::DebugInfo::kSideEffects;if (should_set_has_no_side_effect) {CHECK(self->IsJSFunction() &&i::JSFunction::cast(*self).shared().IsApiFunction());i::Object obj =i::JSFunction::cast(*self).shared().get_api_func_data().call_code();if (obj.IsCallHandlerInfo()) {i::CallHandlerInfo handler_info = i::CallHandlerInfo::cast(obj);if (!handler_info.IsSideEffectFreeCallHandlerInfo()) {handler_info.SetNextCallHasNoSideEffect();}}}i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);Local<Object> result;has_pending_exception = !ToLocal<Object>(i::Execution::New(isolate, self, self, argc, args), &result);if (should_set_has_no_side_effect) {i::Object obj =i::JSFunction::cast(*self).shared().get_api_func_data().call_code();if (obj.IsCallHandlerInfo()) {i::CallHandlerInfo handler_info = i::CallHandlerInfo::cast(obj);if (has_pending_exception) {// Restore the map if an exception prevented restoration.handler_info.NextCallHasNoSideEffect();} else {DCHECK(handler_info.IsSideEffectCallHandlerInfo() ||handler_info.IsSideEffectFreeCallHandlerInfo());}}}RETURN_ON_FAILED_EXECUTION(Object);RETURN_ESCAPED(result);
}

使用原生的NewInstanceWithSideEffectType置成SideEffectType::kHasNoSideEffect也没有效果,

/*** Options for marking whether callbacks may trigger JS-observable side effects.* Side-effect-free callbacks are allowlisted during debug evaluation with* throwOnSideEffect. It applies when calling a Function, FunctionTemplate,* or an Accessor callback. For Interceptors, please see* PropertyHandlerFlags's kHasNoSideEffect.* Callbacks that only cause side effects to the receiver are allowlisted if* invoked on receiver objects that are created within the same debug-evaluate* call, as these objects are temporary and the side effect does not escape.*/
enum class SideEffectType {kHasSideEffect,kHasNoSideEffect,kHasSideEffectToReceiver
};

所以目前针对于这个问题,尚没有解决方案。

【v8】一些关于内存泄漏的踏坑相关推荐

  1. 有意思的 Node.js 内存泄漏问题

    作者:elvinpeng,腾讯 WXG 前端开发工程师 Node.js 使用的是 V8 引擎,会自动进行垃圾回收(Garbage Collection,GC),因而写代码的时候不需要像 C/C++ 一 ...

  2. Node.js 应用的内存泄漏问题的检测方法

    Debugging Memory Leaks in Node.js Applications Node.js 是一个基于 Chrome 的 V8 JavaScript 引擎构建的平台,用于轻松构建快速 ...

  3. 设置log缓存_全局变量、事件绑定、缓存爆炸?Node.js内存泄漏问题分析

    作者:elvinpeng,腾讯 WXG 前端开发工程师 Node.js 使用的是 V8 引擎,会自动进行垃圾回收(Garbage Collection,GC),因而写代码的时候不需要像 C/C++ 一 ...

  4. Android 解决XXX Layout leaked 使用Navigation 踩坑 XML内存泄漏

    Android 解决XXX Layout leaked 使用Navigation 踩坑 XML内存泄漏 报错日志 排查过程 泄漏原因 解决方案 最近维护一个项目,一个内存泄漏的的原因查了很久,这里记录 ...

  5. 【学习react中遇到的坑:内存泄漏报错】

    学习react中遇到的坑:内存泄漏报错 对就是这个错误 Can't perform a React state update on an unmounted component. This is a ...

  6. 图解 Google V8 # 22 :关于内存泄漏、内存膨胀、频繁垃圾回收的解决策略(完结篇)

    说明 图解 Google V8 学习笔记 几种内存问题 内存问题可以定义为三类: 内存泄漏 (Memory leak):导致页面的性能越来越差: 内存膨胀 (Memory bloat):导致页面的性能 ...

  7. 填坑总结:python内存泄漏排查小技巧

    摘要:最近服务遇到了内存泄漏问题,运维同学紧急呼叫解决,于是在解决问题之余也系统记录了下内存泄漏问题的常见解决思路. 本文分享自华为云社区<python内存泄漏排查小技巧>,作者:luti ...

  8. Android高德地图踩坑记录-内存泄漏问题

    1.问题现象 最近做项目优化,在查找app可能存在的内存泄漏地方,项目中有用到高德地图SDK,有一个页面有展示地图,每次退出该页面的时候,LeakCanary老是提示有内存泄漏,泄漏的大概信息如下: ...

  9. php 在对象中递归 坑,PHP_PHP对象递归引用造成内存泄漏分析,通常来说,如果PHP对象存在递 - phpStudy...

    PHP对象递归引用造成内存泄漏分析 通常来说,如果PHP对象存在递归引用,就会出现内存泄漏.这个Bug在PHP里已经存在很久很久了,先让我们来重现这个Bug,示例代码如下: class Foo { f ...

最新文章

  1. X-Shell远程连接虚拟机
  2. ASP调用带参数存储过程的几种方式
  3. 中南月赛 1313: ZZY的宠物
  4. 動態修改SiteMapPath路徑
  5. MinGW 64的安装 - 官网sourceforge安装失败非翻墙解决办法
  6. http请求前后监听工具
  7. java面向服务编程_设计面向领取驱动(DDD)的微服务
  8. 联手三年,获取数千名客户,阿里云如何重构 Elastic 开放免费的技术?
  9. Hart/Hart-IP协议 介绍、分析和应用
  10. 实验7-3-8 输出大写英文字母
  11. 梦三国2英霸模式貂蝉攻略(玩大流)
  12. ElasticSearch教程-索引的介绍
  13. 延云YDBYA100安装部署文档
  14. 【2021版】吐血整理_专升本计算机文化基础—Excel2010
  15. Java P1413 滑雪
  16. oracle修改数据前备份,Oracle 之利用BBED修改数据块SCN—-没有备份数据文件的数据恢复...
  17. 【算法设计与分析】1.主定理
  18. 华为云空间满了怎么清理_华为云空间满了怎么清理
  19. Linux命令-完整手册
  20. JVM面试经典(BAT必面)

热门文章

  1. 35 WM配置-作业-定义需求类型
  2. 17 合作伙伴角色‘OA’不允许用于科目组xxxx的供应商
  3. android xml对象,对象转成xml(并且序列化xml)在android中
  4. 苹果cms模板_苹果cms是什么东西?
  5. linux c语言 udp 接收和发送数据用同一个端口_网络编程基础入门及TCP,UDP
  6. telnet后为啥打开的时防火墙_飞机起降时为啥要打开遮光板?机餐为啥总觉得不好吃?答案看这里...
  7. python中curve fit_scipy.optimize.curve_fit函数用法解析
  8. php 三种传递函数,php – 是否可以将传递函数传递给包含的文件?
  9. Python enumerate() 函数
  10. 1.x和2.x的区别