Javascript 是否曾经垃圾收集函数或常量?

问题描述 投票:0回答:2

假设我的应用程序中有一个文件,仅包含数百个导出函数,但我的应用程序中只有一个很少使用的部分使用它们。像这样的文件:

export function a() {
  ..
}

export function b() {
  ..
}

export function c() {
  ..
}

export function d() {
  ..
}

当导航到应用程序的该部分时,会调用这些函数(通过导入然后执行),但如果用户不再去那里,这些函数是否仍然占用内存,或者最终被释放?

将这些函数定义在类中会更有效吗?然后在导航到应用程序的该部分时实例化该类?因为当用户离开应用程序的该部分时,因为引用将超出范围,那么内部的函数将被取消分配?

同样,如果您在应用程序的同一部分中有数字或对象,如下所示:

export const NUM_A = 55;
export const NUM_B = 66;
export const NUM_C = 77;
export const NUM_D = 88;

我假设数字只是内联的,但如果它们是像这样的复杂对象怎么办?

export const OBJ_1 = {
  a: 3,
  b: 4,
  c: 5
}; 

export const OBJ_2 = {
  a: 55,
  b: 66,
  c: 77
}; 

这些在进口到某个地方后会“永远存在”吗?或者它们最终会被垃圾收集吗?这一切是如何运作的?

javascript memory garbage-collection v8 internals
2个回答
2
投票

垃圾收集取决于全局上下文中的可达性(或缺乏可达性)。

函数可能会被垃圾收集,但您必须将它们从顶层容器中删除,即

var foo = () => console.log("test");
window.foo = undefined;

或者在node.js上:

var foo = () => console.log("test");
global.foo = undefined;

但是常量无法更改,因此它们不能被垃圾收集


0
投票

当导航到应用程序的该部分时,会调用这些函数(通过导入然后执行),但如果用户不再去那里,这些函数是否仍然占用内存,或者最终被释放?

我认为“函数占用内存”根本没有意义,一个“函数”可以通过多种方式占用内存:

(1) 函数的源代码,因此文件中声明由网络浏览器加载的函数的部分

当您打开调试器时,您可以看到源文件(浏览器无需执行第二次请求),因此只要页面打开,就会保留源文件(而且我猜保留这几千字节/兆字节并不重要)。它将在第一次导入时加载(如果您推迟加载脚本),因此可能会推迟到您第一次需要它为止。

(2) 从模块导入时收到的函数对象,您可以调用它。一旦导入一次,它也不能根据需要被丢弃/重新创建,因为您总是可以加载一些执行

(await import("module")).a === (await import("module")).a
的新代码,然后浏览器需要返回 true。这些函数对象可能非常小(几个字节),因此“内存中包含数百个函数对象”将占用几百个字节 - 因此很可能不会导致应用程序 OOM。

(3) 函数的“运行时表示”,因此引擎可以实际执行的东西。起初,这可能是一些 AST,对于更热门的函数,可能是一些特定的 VM 字节码,对于真正热门的函数,可能是一些 JIT 编译的本机字节码。当函数被实际调用时,引擎总是可以从源代码 (1) 中重新创建这些内容,因此,如果它认为该函数永远不会再次被调用,它可能会在某个时候丢弃这些内容。它还可能会推迟创建此函数,直到第一次调用该函数,因为即使构建 AST 也是昂贵的(假设函数平均从未被调用)。

(4) 函数在运行时处理的值,这些值是在函数运行时创建的,并且只要可以读取它们就一直存在。

将这些函数定义在类中会更有效吗?

不。方法是一个函数(具有一些特殊属性)。

然后在导航到应用程序的该部分时实例化该类?因为当用户离开应用程序的该部分时,因为引用将超出范围,那么内部的函数将被取消分配?

不。方法(“函数对象”)存储在类函数对象原型上,而不是实例上。

同样,如果您在应用程序的同一部分中有数字或对象,如下所示:

export const NUM_A = 55;
export const NUM_B = 66;
export const NUM_C = 77;
export const NUM_D = 88;

我假设数字只是内联的

如果它们被内联,它们甚至会在内存中出现两次,一次在常量中,一次在它们被内联的 JIT 编译代码中。

[对象呢]这些东西被导入到某个地方后会“永远存在”吗?或者它们最终会被垃圾收集吗?这一切是如何运作的?

函数对象和对象没有区别。如果同一个文件被导入两次,

import(...)
保证返回相同的实例,因此引擎无法卸载对象或函数对象。


总结一下:您当前担心内存中的几个字节的函数对象/对象,而您更应该担心缩小 JavaScript 源代码,因为这会消耗更多内存。

© www.soinside.com 2019 - 2024. All rights reserved.