Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/478.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/42.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 节点不';我不能正确地控制我的目标_Javascript_Node.js_Garbage Collection_Libxml Js - Fatal编程技术网

Javascript 节点不';我不能正确地控制我的目标

Javascript 节点不';我不能正确地控制我的目标,javascript,node.js,garbage-collection,libxml-js,Javascript,Node.js,Garbage Collection,Libxml Js,这里有一个简单的例子: let html = `<<some huge html file>>` var libxmljs = require("libxmljs"); class MyObject{ constructor(html){ this.doc = libxmljs.parseHtml(html); this.node = this.doc.root() } } let obj for(var i = 0; i < 1000

这里有一个简单的例子:

let html = `<<some huge html file>>`
var libxmljs = require("libxmljs");

class MyObject{
  constructor(html){
    this.doc = libxmljs.parseHtml(html);
    this.node = this.doc.root()
  }
}

let obj

for(var i = 0; i < 100000; i++){
  obj = new MyObject(html)
  // if I uncomment the next line it works fine
  // obj.node = null
  console.log(i)
}
let html=``
var libxmljs=require(“libxmljs”);
类MyObject{
构造函数(html){
this.doc=libxmljs.parseHtml(html);
this.node=this.doc.root()
}
}
让obj
对于(变量i=0;i<100000;i++){
obj=新的MyObject(html)
//如果我取消注释下一行,它可以正常工作
//obj.node=null
控制台日志(i)
}
当我运行它时,脚本很快就会耗尽内存,显然是因为obj.node没有正确地进行垃圾收集。当我认为我已经完成时,如何确保在不显式地将其设置为null的情况下发生这种情况?

如果不将引用专门存储在类实例中,则对象
.root()
返回的GC似乎更多。内存使用情况似乎仍然相当泄漏,因为分配的堆的总量从未回收。节点本身使用的内存似乎是堆上内存的两倍,用于处理本机libxml代码。也许会像臭虫一样发出嘎嘎声

不将对象存储在类实例中,而是通过类实例传递对象效果更好

class MyObject{
  constructor(){
    this.doc = libxmljs.parseHtml(html)
  }
  get node(){
    return this.doc.root()
  }
}
使用普通对象也更有效

function myObject(){
  let doc = libxmljs.parseHtml(html)
  let node = doc.root()
  return {
    doc: doc,
    node: node,
  }
}

作为替代方案,您可以尝试以下方法之一。

TL;DR:问题在于库而不是节点

长话短说

下面是一个稍微修改过的代码

var heapdump = require('heapdump');
const fs = require('fs');
var libxmljs = require("libxmljs");

const content = fs.readFileSync('./html2.htm');
let id = 0;

class MyObject{
  constructor(){
    this.doc = libxmljs.parseHtml(content);
    this.node = this.doc.root()
  }
}

let obj;

function createObject () {
  obj = new MyObject(content);
};


try {
  for(var i = 0; i < 3000; i++){
    createObject();
    // if I uncomment the next line it works fine
    // obj.node = null
    console.log(i);
    if (i === 50) {
      heapdump.writeSnapshot('/Users/me/3.heapsnapshot');
    }
    if (i === 100) {
      heapdump.writeSnapshot('/Users/me/4.heapsnapshot');
    }
    if (i === 150) {
      heapdump.writeSnapshot('/Users/me/5.heapsnapshot');
    }

  }
  console.log('done');
}
catch(e) {
  console.log(e);
}
var heapdump=require('heapdump');
常数fs=要求('fs');
var libxmljs=require(“libxmljs”);
const content=fs.readFileSync('./html2.htm');
设id=0;
类MyObject{
构造函数(){
this.doc=libxmljs.parseHtml(内容);
this.node=this.doc.root()
}
}
让obj;
函数createObject(){
obj=新的MyObject(内容);
};
试一试{
对于(变量i=0;i<3000;i++){
createObject();
//如果我取消注释下一行,它可以正常工作
//obj.node=null
控制台日志(i);
如果(i==50){
heapdump.writeSnapshot('/Users/me/3.heapsnapshot');
}
如果(i==100){
heapdump.writeSnapshot('/Users/me/4.heapsnapshot');
}
如果(i==150){
heapdump.writeSnapshot('/Users/me/5.heapsnapshot');
}
}
console.log('done');
}
捕获(e){
控制台日志(e);
}
下面是我们在代码(3和4)中采用的heapdump diff的相关部分

当我们看到4和5重泵时,甚至是清晰的

从这些堆堆中,我们可以得出以下几点结论:

  • JS部件中没有内存泄漏
  • heapdump的大小与我们在htop/top/activity monitor上看到的进程大小不匹配,具体取决于您的操作系统。(12 MB的heapdump而RAM中只有很少的Gb)
Heapdump只会导致内存泄漏。因为这个库有c代码,所以heapdump不会捕获将存在的泄漏

我不确定如何从该库中捕获转储,或者为什么将其设置为null会允许释放内存,但可以安全地假设node gc正在尽其所能


希望这能有所帮助

但Node gc为什么不使用它呢?我觉得这就像节点中的一个bug。我觉得使用析构函数可以解决我的问题,但是节点团队认为它不需要析构函数,而我的示例表明它可能需要。不过我对Node还不熟悉,所以我希望我忽略了一些显而易见的东西。Node通常会这样做,如果你用普通的JS对象做的话,它会很好。libxmljs基于本机libxml2库,这为更多内存问题提供了可能性。基于JS的解析器可能会慢一些,但不太可能出现这样的问题。目前还不清楚node为什么不能正确地gc'ng我的对象。听起来节点确实需要析构函数,尽管它声称不需要。一个析构函数可以很好地解决我的问题。这个想法是你不需要析构函数在正常的操作虽然。。。就像我说的,
libxmljs
模块在它的原生C数据和JS对象之间保留引用的方式看起来像个bug。嗯,你使用“正常操作”对我来说是个问题。我觉得这是一个正常的操作,应该有一个简单的方法来确保对象被正确地垃圾收集。我想等待其他人对此发表意见,恕我冒犯,谢谢你的回答。谢谢,这是有用的信息。我仍然不确定node是否尽了全力。有趣的是,
node--trace\u gc
确实跟踪了JS堆中的一些对象保留。旧空间的增长速度约为操作系统上实际进程内存速度的1/2
process.memoryUsage()
会在
外部
跟踪内存的顶部显示相同的内容