如何检测JavaScript中的内存限制?

How do you detect memory limits in JavaScript?

本文关键字:内存 JavaScript 何检测 检测      更新时间:2023-09-26

浏览器可以对JavaScript对象中存储的数据量施加任何限制吗?如果是这样,有什么方法可以检测到这个极限吗?

默认情况下,Firefox似乎没有:

var data;
$("document").ready(function() {
  data = [];
  for(var i = 0; i < 100000000000; i++) {
    data.push(Math.random());
  }
});

继续消耗越来越多的内存,直到我的系统耗尽。

既然我们不能检测到可用内存,有没有其他的方法来告诉我们正在接近这个极限?

我正在开发的应用程序依赖于非常快的响应时间才能使用(这是核心卖点)。不幸的是,它也有一个非常大的数据集(超过了在较弱的客户机机器上可以容纳的内存)。通过战略性地预先加载数据(猜测将被点击的内容),可以大大提高性能。当猜测不正确时,回退到从服务器加载数据可以工作,但是服务器往返并不理想。充分利用每一点内存,我可以使应用程序尽可能的高效。

现在,它允许用户"配置"他们的性能设置(最大数据设置),但用户不想管理它。此外,由于它是一个web应用程序,我必须处理用户在每台计算机上的设置(因为功能强大的桌面比旧iPhone的内存要大得多)。如果它只使用系统上可用的最佳设置,那就更好了。但是猜测过高也会在客户端计算机上引起问题。

虽然这在某些浏览器上是可能的,但正确的方法应该是决定典型客户可以接受的限制,并可选地提供一个UI来定义他们的限制。

大多数重型web应用程序的JavaScript堆大小约为10MB。似乎没有一个指导方针。但我可以想象,在台式机上使用超过100MB的数据,在移动设备上使用超过20MB的数据并不是很好。之后的所有内容都可以查看本地存储,例如文件系统API(您可以完全将其设置为PERSISTENT)

这个答案背后的原因如下。几乎从来没有用户只运行一个应用程序。在浏览器只打开一个选项卡的情况下更是如此。最终,消耗所有可用内存从来都不是一个好的选择。因此,不需要确定上边界。

用户想要分配给web应用程序的合理内存量是一个猜测工作。例如,高度交互的数据分析工具在JS中是很可能的,可能需要数百万个数据点。一种选择是默认设置较低的分辨率(例如,每天而不是每秒测量)或较小的窗口(一天vs十年秒)。但是,随着用户不断探索数据集,将需要越来越多的数据,这可能会削弱代理端的底层操作系统。

好的解决方案是采用一些合理的初始假设。让我们打开一些流行的web应用程序,进入开发工具-配置文件-堆快照查看:

  • fb: 18.2 mb
  • GMail: 33 MB
  • Google+: 53.4 MB
  • YouTube: 54 MB
  • Bing Maps: 55 MB

注意:这些数字包括DOM节点和JS对象在堆上。

似乎在那时,人们开始接受一个有用的网站有50MB的内存。(更新2022:现在平均接近100MB)一旦你建立了你的DOM树,用测试数据填充你的数据结构,看看多少是可以保留在RAM中。

在Chrome中使用类似的测量方法,可以看到平板电脑和手机上相同网站的消耗,顺便说一句。

这就是我如何在台式机上达到100mb,在手机号码上达到20mb。似乎也很合理。当然,对于偶尔的重度用户来说,有一个将最大堆提高到2gb的选项会很好。

现在,如果每次从服务器抽取所有这些数据的成本太高,你该怎么办?

一件事是使用应用程序缓存。它确实会给版本管理带来一些麻烦,但允许您存储大约5mb的数据。比起存储数据,保存应用程序代码和资源更有用。

除此之外,我们有三个选择:

  • SQLite - 支持有限,似乎要放弃
  • IndexDB -更好的选择,但支持还不是普遍的(我可以使用它吗?)
  • <
  • 文件系统API/gh>
其中,FileSystem 是最受支持的,可以使用相当大的存储块。

在Chrome中答案是肯定的!

进入控制台,输入:

performance.memory.jsHeapSizeLimit; // will give you the JS heap size
performance.memory.usedJSHeapSize; // how much you're currently using
arr = []; for(var i = 0; i < 100000; i++) arr.push(i);
performance.memory.usedJSHeapSize; // likely a larger number now

我想你会需要这样的东西:

const memory = navigator.deviceMemory
console.log (`This device has at least ${memory}GiB of RAM.`)

您可以查看以下内容:https://developer.mozilla.org/en-US/docs/Web/API/Navigator/deviceMemory

注意:此功能不支持所有浏览器

由于web应用程序不能访问任何与系统相关的信息(如可用内存量),并且由于您不希望必须要求用户手动设置其性能设置,因此您必须依赖于允许您在不询问用户的情况下获得有关用户系统(可用内存)的此类信息的解决方案。似乎不可能?嗯,几乎…

但是我建议你做以下事情:制作一个Java applet,它将自动获得可用的内存大小(例如使用Runtime.exec(...)与适当的命令),提供你的applet签名,并将该信息返回到服务器或直接到网页(使用JSObject,参见http://docs.oracle.com/javafx/2/api/netscape/javascript/JSObject.html)。

然而,这将假设您的用户都可以在他们的浏览器中运行Java applet,但情况并非总是如此。因此,你可以要求他们在他们的机器上安装一个小软件,它可以测量你的应用应该使用多少内存而不会导致浏览器崩溃,并将该信息发送给你的服务器。当然,你必须为每个操作系统和体系结构(Windows、Mac、Linux、iPhone、Android……)重写那个小程序,但为了获得一些性能,重写整个应用程序要简单得多。这是一种介于两者之间的解决方案。

我不认为有一个简单的解决办法。无论您选择做什么,都将存在一些缺点。请记住,web应用程序并没有快速的名声,所以如果性能很重要,你应该考虑编写一个传统的桌面应用程序。