Javascript 内存处理与性能
我正在构建一个WebGL游戏,我已经走了这么远,我已经开始研究性能瓶颈。我可以看到当GC进行时FPS中有很多小的下降。因此,我创建了一个小型内存池处理程序。在我开始使用GC之后,我仍然看到很多GC,我可能会怀疑我出了什么问题 我的内存池代码如下所示: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
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)
来实现,假设您不想对该类进行子类化。