创建函数是不是消耗更多内存
Posted
技术标签:
【中文标题】创建函数是不是消耗更多内存【英文标题】:Does creating functions consume more memory创建函数是否消耗更多内存 【发布时间】:2011-11-19 01:25:31 【问题描述】:// Case A
function Constructor()
this.foo = function()
...
;
...
// vs
// Case B
function Constructor()
...
;
Constructor.prototype.foo = function()
...
人们建议使用原型的主要原因之一是.foo
在原型的情况下被创建一次,而this.foo
在使用其他方法时被创建多次。
但是人们希望口译员可以优化这一点。这样在案例 A 中只有一个函数 foo
的副本。
当然,由于闭包,您仍然会为每个对象拥有一个唯一的作用域上下文,但与每个对象的新函数相比,这具有更少的开销。
现代 JS 解释器是否优化了案例 A,所以函数 foo
只有一个副本?
【问题讨论】:
【参考方案1】:是的,创建函数会占用更多内存。
...而且,不,解释器不会将案例 A 优化为单个函数。
原因是the JS scope chain 要求函数的每个实例在创建时捕获可用的变量。这就是说,modern interpreters 是 better 关于案例 A 的情况,但主要是因为闭包函数的性能在几年前是一个已知问题。
出于这个原因,Mozilla 向 avoid unnecessary closures 表示,但闭包是 JS 开发人员工具包中最强大且最常用的工具之一。
更新:刚刚运行 this test,它使用 node.js(它是 V8,Chrome 中的 JS 解释器)创建了 1M 的构造函数“实例”。使用caseA = true
我得到了这个内存使用情况:
rss: 212291584, //212 MB
vsize: 3279040512, //3279 MB
heapTotal: 203424416, //203 MB
heapUsed: 180715856 //180 MB
caseA = false
我得到这个内存使用情况:
rss: 73535488, //73 MB
vsize: 3149352960, //3149 MB
heapTotal: 74908960, //74 MB
heapUsed: 56308008 //56 MB
因此,闭包函数肯定会消耗更多的内存,几乎是 3 倍。但从绝对意义上讲,我们只是在谈论每个实例约 140-150 字节的差异。 (但是,这可能会增加,具体取决于您在创建函数时拥有的范围内变量的数量)。
【讨论】:
我们能否提供一些定义“更好”和“现代解释器”的参考资料 您的测试也与我在我的测试中发现的相匹配——我还在函数内部添加了一些大代码块来测试这是否会使内存气球更快——但事实并非如此。 .. 函数内的代码不需要额外的内存。 哦 - 我还注销了测试前后的内存使用情况,以测量创建对象之前的差异 可能值得对照 chrome canary v32 进行检查 - 看起来有一些改进。【参考方案2】:我相信,在节点中进行一些简短测试后,在案例 A 和 B 中,内存中只有一个函数 foo
的实际代码副本。
案例 A - 为 Constructor()
的每次执行创建一个函数对象,存储对函数代码的引用及其当前执行范围。
案例 B - 只有一个作用域,一个函数对象,通过原型共享。
【讨论】:
你能发布你的测试代码吗?我确信解释器内部正在进行一些优化以避免每次解析函数代码,但是每次通过构造函数都必须捕获对任何范围内变量的引用,以便它们可以正确调用函数时解决。 @broofa - 将我的代码与您的代码进行比较,它基本上是相同的...... :) - 我只是从函数内部的其他东西中转储了 40 行代码来测试......【参考方案3】:javascript 解释器也没有优化原型对象。它只是每种类型只有一个(多个实例引用)的情况。另一方面,构造函数创建新实例和其中定义的方法。所以根据定义,这真的不是解释器“优化”的问题,而是简单地理解正在发生的事情。
附带说明,如果解释器尝试合并实例方法,如果您决定更改特定实例中 one 的值,您会遇到问题(我希望不要将头痛添加到语言中) :)
【讨论】:
编译器确实优化了函数,但它并没有优化scopecontext。 每个解释器如何处理重复项似乎并不是问题,但解释器需要在多个实例方法之间建立差异,并且这种差异会消耗更多内存 对于案例 A,我希望编译器看到构造函数中没有局部变量,因此无需将其变量对象保留在实例的范围链上。如果使用局部变量,除非它足够聪明,如果内部函数不引用它们,则可以优化变量对象。无论如何,我会使用原型方法,因为它更整洁、更易于维护(当然是 IMO)。以上是关于创建函数是不是消耗更多内存的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Numpy 和 Pandas 数组比源数据消耗更多内存? [关闭]
“检查指针进程”在 Postgres 中消耗更多内存。如何控制它?