IDBRequest对象在内存中的哪里?

问题描述 投票:1回答:1

这似乎是一个奇怪的问题,但是我试图了解我的代码在执行内存方面到底做了什么,以使其尽可能高效。

[当发出诸如req = objectStore.getAll( keyRange );之类的数据库请求,并且返回IDBRequest对象,并且稍后将结果提供给该对象的result属性时,该对象在哪里创建?是否与GC分配和释放的任何其他JS对象一样?并且变量req只是对其的引用,因此一旦引用被打破,GC就会“知道”该对象不可访问并释放内存?

如果在很短的时间间隔内发出了许多这样的请求,是否有一种方法可以不为每个结果消耗额外的RAM?

例如,我感兴趣的过程是单击按钮通过Promise.allSettled调用两个promise(一个写和一个读),一个将当前状态写入数据库,另一个将检索新数据并构建其中的文档片段。如果两者都满足,则该片段将替换DOM中的一个节点。

[如果用户快速单击此数据,则每个read/getAll都会返回一个IDBRequest,其结果是对象数组,并且看起来会消耗越来越多的RAM,直到GC运行为止。我可以观察到内存最终已释放,但是我想知道是否有一种方法可以避免这种情况的发生。由于我知道这些对象的最大大小,因此我可以将IDBRequest写到一个现有对象,就像模板对象一样,并且只需要其中一个或两个,例如一个用于当前,一个用于新请求,而不是不断添加新对象,直到GC释放那些认为无法访问的对象?

谢谢您考虑我的问题。


感谢有关在哪里分配IDBRequest对象的答案,以及有关避免内存泄漏的建议。只是为了进一步说明我正在观察的内容,并想知道是否可能,我添加了此注释。

我的代码中没有声明一个全局变量,它们都存在于函数中或属于函数对象的属性。最终在indexedDB中工作了大部分I / O之后,我开始考虑当用户在我的应用程序中工作一两个小时时会发生什么。即使我在所有构建和测试过程中都没有发现问题,从长远来看,内存使用量会持续增长吗?

我用500个数据包填充了数据库,这意味着需要一个以上的数据库对象来构建新的DOM节点;每个节点最多可以容纳15到60个对象,具体取决于用户所构建的对象。因此,我将500个数据包中的每个数据包都由60个对象组成,并使这些对象的尺寸过大,无法进行测试,远远超出了适当使用该工具的预期范围。

然后通过setInterval,从数据包1到500每500毫秒调用一次保存状态,获取和构建承诺;而且我只观察了maro级别的数据使用情况。结果似乎是,在任何一次GC运行之间,RAM中可能存在大约一百个这些数据包。随着数据包的获取,节点的建立和更换,RAM的使用量在从数据包1到500的遍历过程中稳定增加并下降了大约5倍。在丢弃之前,每次增加的最大水平都比前一个略高。完成后约45秒左右,内存将返回到setInterval开始时的大致位置。

因此,幸运的是,我认为没有内存泄漏。但是,RAM使用情况与本article中有关使用对象池的描述非常相似。我对“减少内存流失,减少垃圾收集税”标题下的图表感兴趣-这种锯齿模式消耗的内存远远超过了任何时候所需的内存,而第二个图表就像较小,更高级,并且总共需要运行较少的GC。

并且几乎在最后,对此SO question的第一个答案写道,这导致GC也必须跟踪更多对象。

我不确定GC是否会以较低的总RAM消耗运行,还是会等到达到某个最大级别。当然,我可以在我的机器上进行测试,但这总体上并不是很确定。

我不是在开发游戏,暂停GC运行也不是问题;用户绝对不应在250秒内点击500个数据包,也永远不会有500个如此荒谬的数据包。也许,这种检验是不现实的;但目的是试图延长使用该工具的时间,并在整个过程中生成许多小物体。即使是一次较小的编辑的获取/输入,每次也会创建一个新对象。这些是我以前从未考虑过的概念,而只是专注于如何首先使I / O准确地工作。

[至少要考虑有多少个对象在RAM中停留一会儿,等待被垃圾回收,似乎总是在任何时候都简单地保留当前数据包是合理的,因此对于编辑。只需在RAM中编辑对象并仅使用get操作即可。然后,将永远不会创建所有那些put请求结果对象以进行编辑。但这并不能消除对象容纳新请求的完整数据包的需求。

我知道浏览器的GC程序应该可以使所有这些操作变得更加容易,但是这样做似乎会使编码人员失去很多控制权;我在其他问题上看到的关于SO的建议通常是不用担心,除非您遇到问题。我充其量只是一个业余爱好者,但我更希望从一开始就了解后台发生的事情和代码。也许我固执己见,不管处理器的功能和RAM的大小如何,我的小工具都应该使用必要的资源,否则我就没有完成工作。

我仍然不知道对象池是否是一种好的技术,但是即使是这样,从索引数据库中检索数据似乎也不可行,因为IDBRequest对象总是被重新创建并且可以永远不要写入现有对象。

再次感谢您的解释。

indexeddb
1个回答
0
投票

IDBRequest对象的result属性与其他任何对象一样,将数据保存在内存中。当没有东西引用请求对象时,内存是可回收的。无法为每个新结果不消耗额外的内存。分配是内存获取。

Chrome的政策是,在存在争用之前,将事物保留在虚拟内存中不是问题。在没有证据表明会造成性能影响之前,您不要担心内存使用过多。大多数情况下不是。

但是,您可以在代码中查找保留对请求对象的引用的位置。如果永久保留对它们的引用,则这些对象将永远不会被释放并且无法回收。非常类似于带有事件侦听器的旧IE错误,这是内存泄漏的一种形式。

避免这种行为的surefire新手证明方法是只在函数中使用变量,而不是全局变量。每个函数调用变量通常在作用域退出时回收,当函数调用完成时,并不需要太多考虑,也没有明确的代码尝试对已经为您管理的内容进行微管理。例如,不需要在每次使用变量后都将所有变量声明为get而不是let并设置constvalue = undefined;。因此,我将查看您的代码,并查看在超出创建它们的函数的生命周期之外,对变量的引用将保留在哪里。这些是罪魁祸首。

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