【问题标题】:Garbage collecting takes too long in my JS real-time app我的 JS 实时应用程序中的垃圾收集时间太长
【发布时间】:2014-06-05 18:29:58
【问题描述】:

所以我正在开发这个相当复杂的实时应用程序。我有一个音频引擎,它每 100 毫秒触发一次繁重的音频处理功能,以填充立即播放的缓冲区。 如果这些音频功能运行得太晚,即使运行一次,您也会听到声音卡顿

大部分时间一切正常。 但是,V8 触发垃圾收集器时,大约需要 150ms 才能完成一轮,从而触发上述裂缝

那么问题来了:我怎样才能获得更短的垃圾回收?

几点说明:

我们可以尝试分配更少的变量,以便堆增长得更慢,但我想这并不能解决问题:即使触发 GC 的频率降低了一半,我看不出有任何理由运行集合快点。我宁愿让它运行两倍的频率和一半的时间。

我已经阅读了一些关于 V8 的 GC 的内容。我知道我无法直接控制 GC。我知道它有一个短期的过程和一个长期的过程(mark & sweep)。我想是后者导致了这个问题。但是我不知道它花了这么长时间的确切原因:是删除的数据量还是浏览的数据结构?了解这一点可能会有所帮助。

我已经尝试过广泛使用 Chrome 开发工具,并且根据 this article 我需要使用“记录堆分配”模块。但是当我运行一个并并行查看时间线时,我可以看到它一直在触发垃圾收集,就像堆快照一样,所以我无法真正追踪到底是什么让我的内存增长。

我们没有任何内存泄漏,这已经过测试。没有常规的 DOM 访问,也没有创建事件监听器。鉴于具有高 FPS 的应用数量众多,我想这是一个常见问题...请帮助!

编辑

我们想到的另一种解决方案是故意将我们的数据存储在内存泄漏中,以便在我们明确决定释放内存之前 GC 不会运行。这听起来像一个邪恶的黑客,有人做过吗?你怎么看?

【问题讨论】:

标签: javascript garbage-collection real-time google-chrome-devtools v8


【解决方案1】:

您可以尝试实现“对象池”设计模式。基本原则是重用变量而不是创建一个删除它们。最好按对象类型设置一个池。

这是一个非常基本的实现。

var pool = [];
var poolRelease = function(obj) {
  pool.push(obj);
};
var poolGet = function() {
  // You could add parameters to the function to directly set the values of the object.
  if (pool.length) {
    return pool.pop();
  }
  // We don't have preexisting object, create it (can be anything).
  return {x: 0, y: 0};
}

// Then in the code:
var myObj = poolGet();
myObj.x = 20;
// When finished with the object move it back to the pool to avoid garbage collection.
poolRelease(myObj);

【讨论】:

  • 是的,这绝对是正确的做法(以及其他常见的最佳实践)。我问了这个问题后才发现,这就是游戏开发者一直在做的事情。
  • 对象池在@Winchestro 的第二个链接中进行了解释。这里有一些链接可以更详细地解释这一点(视频特别有趣):youtube.com/watch?v=Op52liUjvSkgameprogrammingpatterns.com/object-pool.htmlhtml5rocks.com/en/tutorials/speed/static-mem-pools
  • 另一件事:我担心随着时间的推移分配更少的内存并不一定会使每个集合更短,只会更罕见。事实证明它确实有效,优化后 GC 运行更短的集合。这是幸运的,因为这是我们唯一能做的!
  • 最后一条评论:我的大部分内存分配来自大量创建 DOM 节点的库。当心这些!
猜你喜欢
  • 2012-06-26
  • 2016-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-16
  • 1970-01-01
相关资源
最近更新 更多