javascript - 每个函数调用在浏览器中的内存管理?
问题描述
在尝试确定如何最有效地执行一系列重复步骤时,我发现我对 Web 浏览器中的内存使用知之甚少。我之前已经多次阅读过有关垃圾收集器和内存泄漏的信息,但仍然很少。我感兴趣的具体场景如下。
getAll
使用键范围内的语句从 indexedDB 检索一组数据对象。数据都是文本,永远不会超过 0.25MB,而且可能总是小于 0.1MB。- 数据对象数组被传递给一个函数,该函数在文档片段中构建一个节点并替换 DOM 中的一个节点。
get/put
当用户修改/添加/删除数据时,状态会使用一个序列保存在数据库中,add
如果一个新对象被构建。这是一次在一个对象上执行的,而不是在整个阵列上执行的。- 用户完成后,将检索下一组数据并再次替换 DOM 节点。用户可以通过他们构建的数据包向前和向后导航。
构建新节点后,不再使用保存数据对象数组的变量,并将其设置为 null 以避免任何潜在的内存泄漏。但我开始思考每次调用函数时数据和内存分配的真正情况。
假设用户快速点击了一系列数据包。每次检索数据并在 DOM 中构建和替换新节点时,是一遍又一遍地使用相同的内存空间,还是每次调用都占用更多空间,而前一次调用中使用的内存稍后被释放GC,这样快速点击十个节点会暂时占用十个节点的数据?我的意思是包括这些步骤中涉及的所有数据,而不仅仅是被替换的 DOM 节点。
我问的一个原因是我正在考虑将数据对象数组保存在 RAM 中,并在用户进行编辑/构建更多对象时更新对象,然后仅使用put
操作将其记录在数据库中而不是get/put
序列中。这让我想知道如果该数组保存在其中一个函数的属性中会发生什么。函数属性的数据分配是否会在每次新调用时重复使用,还是每次都会占用更多空间,直到之前的调用被释放?
我想也许是这样,即使在构建新节点后将变量设置为 null,GC 也可能需要时间来释放内存,这样内存总是被使用,它可能一次只保存一个数据包并消除了get
等待onsuccess
事件更新对象然后put
再次返回的需要。
当然,所有这些都可以在get/put
序列中快速运行,但我想了解有关内存的情况;并且,如果将变量设置为 null 并且不将数组保存在 RAM 中确实没有节省任何东西,那么就没有理由使用get
,并且完成的工作越少,在用户使用此工具一小时后,发生这种情况的可能性就越小或者两个,会有内存问题。
感谢您考虑我相当新手的问题。
谢谢你的意见。尽管它们很有趣,但它们并不真正关心我在问什么。我不是在询问内存泄漏,而只是评论说在函数结束时将变量设置为 null。它们被设置为空,因为我读到如果对内存区域的引用被“损坏”,它有助于 GC 的标记和清除算法识别特定的内存区域可能被释放。而且,如果某种类型的对变量的引用仍然存在,它至少会指向 null 而不是剩余数据的区域。这是否属实,我不确定;但这就是我读到的。我读过很多关于内存泄漏的文章,但只有这三篇,文章 1、文章 2和文章 3我能够轻松地再次找到以提供示例。在文章 3 的第 5 页中,显示了将变量设置为 null 作为一种通过使对象无法访问来防止内存泄漏的方法。
我不明白为什么这个问题会被视为微优化。这只是一个新手问题,当在 GC 周期之间发生多次函数调用时,浏览器中的内存是如何使用的。这只是我一直在研究的一个例子,根本不依赖于 indexedDB,也不依赖于正确编码的应用程序中是否真的存在内存泄漏。我提供的描述可能会让人感到困惑。
如果函数使用局部变量从 indexedDB 对象存储中检索数据对象数组,并且在transaction.oncomplete
处理程序将对该内存区域的引用传递给另一个函数,该函数使用它来构建文档片段并替换 DOM 节点数据会发生什么?两个函数引用数组,一个引用片段。如果通过将指向它们的变量设置为 null(即使未设置为 null)来手动破坏引用,最终 GC 将释放该内存。但是,如果用户快速点击,在很短的时间间隔内重复调用这些函数,即在 GC 周期之间,每次调用都会为数据数组和分片分配一个新的内存区域,这样在 GC 周期之间,可能有十组数据区域保存在 RAM 中等待释放?如果数组保存在检索它的函数的属性中,
正如我之前写的,我想知道是否有一种方法可以为每次调用重用相同的内存区域。如果不可能,并且如果在 GC 周期之间总是有几组数据保存在 RAM 中等待释放,则保留对当前数据集的引用并使用它来减少浏览器执行的工作量以保存当前状态,这本身是一个完全独立的问题,但取决于浏览器如何使用内存。
当我在 Firefox 开发人员工具中观察内存快照时,内存使用量随着我逐步浏览这些数据集、反复检索新数据并构建新片段以替换 DOM 节点而增加;但是该数据量相对较小,并且可能会在 GC 循环运行之前不断累积。从这个观察来看,似乎每次调用都使用了一个新的数据区域,并打破了对前一个数据区域的引用。因此,保持对当前数据集的引用不是内存问题,因为在 GC 周期之间,RAM 中总是有许多这样的内存区域。
尽管如此,我肯定遇到了某种问题,因为在添加 100 个数据包并通过 Next/Previous 按钮向上或向下导航它们之后,数据使用量继续增长,并且几乎全部在 domNode 部分。一开始总共有 7MB,domNode 中 6MB,#document 中 5MB。#document 保持在 5MB,但 domNode 增长到至少 150MB,因为除了上下移动记录、检索数据、构建和替换节点但从未对数据进行编辑之外什么都不做;并且永远不会有超过一个节点,因为在这个测试中,100 个数据包是相同的副本,因此总是替换完全相同的大小。所以,只是getAll
,一遍又一遍地构建一个片段,替换一个 DOM 节点。
谢谢你。
解决方案
推荐阅读
- c++ - C++ 在填充数组时遇到问题
- javascript - discord.js detect multiple channel deletes and multiple bans
- python - 为什么不应用 pandas join-on-join 后缀
- arrays - Julia 截断数组数组的内部维度
- python - Jupyter QtConsole 在哪里保存它过去的命令
- python-3.x - Odoo 12:AttributeError:“int”对象没有属性“get”
- java - Gradle 无法使用 lombok 构建
- python - 带有 MySQL db 的 Python Flask-RestFul - 多个请求同时返回 MYSQL SSL 错误
- javascript - 如何在 contenteditable div 上的每一行旁边显示行号
- powershell - 将文件复制到远程服务器,在加入本地和远程服务器的路径时在PowerShell中复制文件时出现问题