Javascript 内存处理与性能

Javascript 内存处理与性能,javascript,memory-management,garbage-collection,Javascript,Memory Management,Garbage Collection,我正在构建一个WebGL游戏,我已经走了这么远,我已经开始研究性能瓶颈。我可以看到当GC进行时FPS中有很多小的下降。因此,我创建了一个小型内存池处理程序。在我开始使用GC之后,我仍然看到很多GC,我可能会怀疑我出了什么问题 我的内存池代码如下所示: function Memory(Class) { this.Class = Class; this.pool = []; Memory.prototype.size = function() { return this

我正在构建一个WebGL游戏,我已经走了这么远,我已经开始研究性能瓶颈。我可以看到当GC进行时FPS中有很多小的下降。因此,我创建了一个小型内存池处理程序。在我开始使用GC之后,我仍然看到很多GC,我可能会怀疑我出了什么问题

我的内存池代码如下所示:

function Memory(Class) {
    this.Class = Class;
    this.pool = [];

  Memory.prototype.size = function() {
    return this.pool.length;
  };

  Memory.prototype.allocate = function() {
    if (this.pool.length === 0) {
        var x = new this.Class();
        if(typeof(x) == "object") {
            x.size = 0;
            x.push = function(v) { this[this.size++] = v; };
            x.pop = function() { return this[--this.size]; };
        }
        return x;
    } else {
      return this.pool.pop();
    }
  };

  Memory.prototype.free = function(object) {
      if(typeof(object) == "object") {
          object.size = 0;
      }
      this.pool.push(object);
  };

  Memory.prototype.gc = function() {
    this.pool = [];
  };
}
game.mInt = new Memory(Number);
game.mArray = new Memory(Array); // this will have a new push() and size property.
 // Allocate an number
 var x = game.mInt.allocate();

 <do something with it, for loop etc>

 // Free variable and push into mInt pool to be reused.
 game.mInt.free(x);
然后我像这样使用这个类:

function Memory(Class) {
    this.Class = Class;
    this.pool = [];

  Memory.prototype.size = function() {
    return this.pool.length;
  };

  Memory.prototype.allocate = function() {
    if (this.pool.length === 0) {
        var x = new this.Class();
        if(typeof(x) == "object") {
            x.size = 0;
            x.push = function(v) { this[this.size++] = v; };
            x.pop = function() { return this[--this.size]; };
        }
        return x;
    } else {
      return this.pool.pop();
    }
  };

  Memory.prototype.free = function(object) {
      if(typeof(object) == "object") {
          object.size = 0;
      }
      this.pool.push(object);
  };

  Memory.prototype.gc = function() {
    this.pool = [];
  };
}
game.mInt = new Memory(Number);
game.mArray = new Memory(Array); // this will have a new push() and size property.
 // Allocate an number
 var x = game.mInt.allocate();

 <do something with it, for loop etc>

 // Free variable and push into mInt pool to be reused.
 game.mInt.free(x);
game.mInt=新内存(数字);
game.mArray=新内存(数组);//这将有一个新的push()和size属性。
//分配号码
var x=game.mInt.allocate();
//自由变量,并将其推入mInt池以便重用。
游戏。薄荷。免费(x);
我对数组的内存处理是基于使用myArray.size而不是length,它跟踪超维数组(已重用)中的实际当前数组大小

所以我的实际问题是:

使用此方法可以避免GC,并在播放期间保留内存。我在函数中用“var”声明的变量是否仍然是GC,即使它们是作为新类()从内存函数返回的

例如:

var x = game.mInt.allocate();
for(x = 0; x < 100; x++) {
   ...
}
x = game.mInt.free(x);
var x=game.mInt.allocate();
对于(x=0;x<100;x++){
...
}
x=游戏。薄荷。免费(x);
这是否仍然会由于一些幕后的memcopy而导致“var”的内存垃圾收集?(这会使我的内存处理程序变得无用)


我的方法在我尝试获得高FPS的游戏中是否很好/有意义?

所以你让JS实例化一个新对象

var x = new this.Class();
然后将匿名方法添加到此对象,从而使其成为同类之一

x.push = function...
x.pop = function...
因此,现在您使用这个对象的每个地方都很难通过JS引擎进行优化,因为它们现在有不同的接口/隐藏类(equal不完全相同)

此外,您使用这些对象的每个地方都必须实现额外的类型转换,以将
编号
对象转换回原语,并且类型转换也不是免费的。比如,在循环的每次迭代中?甚至可能多次

所有这些开销仅仅是为了存储64位浮点

game.mInt = new Memory(Number);
由于无法更改内部状态,因此无法更改
Number
对象的值,因此这些值基本上是静态的,就像它们的原始对应值一样

TL;博士:
  • 不要汇集本机类型,尤其是原始类型。现在,如果JS不需要处理意外情况,那么它非常擅长优化代码。与具有不同接口的不同对象类似,在使用这些对象之前,首先必须将其转换为基本值

  • 数组大小调整也不是免费的。虽然JS对此进行了优化,并且通常预先分配的内存超过了阵列可能需要的内存,但您仍可能达到该限制,因此强制引擎分配新内存,将所有值移动到新内存并释放旧内存。
    我通常使用链接列表来创建池

  • 不要试图把一切都集中起来。想一想,哪些对象是真正可以重用的,哪些对象是你正在努力使它们符合“可重用性”的叙述。
    我想说的是:如果你只需要在一个对象中添加一个新属性(在它被构造之后),因此你需要删除这个属性来进行清理,那么这个对象不应该被合并

  • 隐藏类:在谈论JS中的优化时,您应该至少在一个非常基本的层次上了解这个主题
    总结:

    • 构造对象后不要添加新属性
    • 为了扩展第一点,请不要
      delete
      s
    • 添加属性的顺序很重要
    • 更改属性的值(甚至其类型)并不重要!除非我们谈论包含函数的属性(又名.methods)。在这里,当我们谈论附加到对象的函数时,优化器可能有点挑剔,所以请避免使用它
  • 最后但并非最不重要的是:优化对象和“字典”对象之间的区别。首先在概念中,然后在代码中
    尝试将所有内容都纳入带有静态接口的模式(这是JS,不是Java)没有任何好处。但是静态类型使优化器的工作更轻松。所以,把这两个词组合起来


原语是按值复制的。=>如果分配值有用的话,我不是舒尔。我只需要做x=5;然后x=未定义…@jonasw您的意思是,例如:x=game.mInt.allocate();游戏。薄荷。免费(x);x=未定义;还是干脆跳过我的内存处理?(x=未定义将导致GC启动,对吗?)。新数字(5);创建一个与原语相比内存消耗相当大的数字对象。非常感谢您的详细解释!这一切都是有道理的,我将重新调查我对池等的需求。“在构建对象后不要添加新属性。”-这可以通过在构造函数末尾调用
object.seal(this)
来实现,假设您不想对该类进行子类化。