我只是想知道函数对象的开销如何。
在 OOP 设计模型中,您可以生成许多对象,每个对象都有自己的私有函数,但如果您有 10,000 多个,我认为这些私有函数对象会产生大量开销。
我想知道是否存在将这些函数移动到实用程序类或外部管理器以节省这些函数对象占用的内存的情况。
我只是想知道函数对象的开销如何。
在 OOP 设计模型中,您可以生成许多对象,每个对象都有自己的私有函数,但如果您有 10,000 多个,我认为这些私有函数对象会产生大量开销。
我想知道是否存在将这些函数移动到实用程序类或外部管理器以节省这些函数对象占用的内存的情况。
这就是 Chrome 处理函数的方式,其他引擎可能会做不同的事情。
让我们看一下这段代码:
var funcs = [];
for (var i = 0; i < 1000; i++) {
funcs.push(function f() {
return 1;
});
}
for (var i = 0; i < 1000; i++) {
funcs[0]();
}
现在,引擎创建了 1000 个函数。
单个函数本身几乎不占用任何内存(在这种情况下为 36 个字节),因为它仅包含一个指向所谓的 SharedFunctionInfo 对象的指针,该对象基本上是对源代码中函数定义的引用*。这称为惰性解析。
只有当你经常运行它时,JIT 才会启动,并创建函数的编译版本,这需要更多的内存。因此,funcs[0]
最终占用 256 个字节:
*) 这并不完全正确。它还保存范围信息和函数的名称和其他元数据,这就是为什么在这种情况下它的大小为 592 字节的原因。
首先,将方法放在对象构造函数原型中是很常见的,因此它们将在给定对象的所有实例之间共享:
function MyObject() {
....
}
MyObject.prototype.do_this = function() {
...
}
MyObject.prototype.do_that = function() {
...
}
另请注意,“函数对象”是常量代码块或闭包;在这两种情况下,大小都与代码无关:
x = [];
for (var i=0; i<1000; i++) {
x.push(function(){ ... });
}
数组中每个元素的大小不取决于代码大小,因为代码本身将在所有函数对象实例之间共享。1000 个实例中的每一个都需要一些内存,但它与其他对象(如字符串或数组)所需的内存量大致相同,并且与函数内部存在多少代码无关。
如果您使用 JavaScript 创建函数,情况会有所不同eval
:在这种情况下,我希望每个函数都占用相当多的时间并且与代码大小成正比,除非在这个级别也完成了一些超级智能缓存和共享。
函数对象实际上确实占用了大量空间。如下所示,对象本身可能不会占用太多空间,但 Function 对象似乎占用更多空间。为了测试这一点,我使用Function("return 2;")
了一个匿名函数数组。
结果正如OP所暗示的那样。这些实际上确实占用了空间。
已创建
从 0 创建100,000 个Function()
导致使用 75.4 MB。我在更受控的环境中运行了这个测试。这种转换更明显一点,它表明每个函数对象将消耗 754 个字节。而这些都是空的。较大的函数对象可能会超过 1kb,这将很快变得重要。在客户端上旋转 75MB 并非易事,并导致 UI 锁定近 4 秒。
这是我用来创建函数对象的脚本:
fs = [];
for(var i = 0; i < 100000; i++ ){
fs.push(Function("return 2;"));
}
调用这些函数也会影响内存级别。调用这些函数会额外增加 34MB 的内存使用量。
叫
这就是我以前对他们的称呼:
for( var i = 0; i < fs.length; i++ ){
for( var a = 0; a < 1000; a++ ){
fs[i]();
}
}
在编辑模式下使用 jsfiddle 很难得到准确的结果,我建议嵌入它。
这些陈述是不正确的,我留下它们是为了让评论保留上下文。
函数对象根本不占用太多空间。可用的操作系统和内存将最终决定如何管理此内存。这不会真正影响您应该担心的任何事情。
在我的电脑上加载时,一个相对空白的 jsfiddle 消耗了 5.4MB 的内存。创建 100,000 个函数对象后,它跃升至 7.5MB。这似乎是每个函数对象的微不足道的内存量(这意味着每个函数对象 21 个字节:7.5M-5.4M / 100k)。