iOS的虚拟内存限制是多少?

时间:2015-09-19 05:39:20

标签: ios memory memory-management

iOS上的虚拟内存使用是否有上限?图必须但却无法追踪它。

2 个答案:

答案 0 :(得分:13)

TL; DR:

操作系统没有强制执行直接显式虚拟内存限制,因此您的应用程序理论上可以分配其整个潜在的逻辑地址空间。对于32位处理器,此大小为4千兆字节,对于64位处理器,此大小为18艾字节。

实际上,可用虚拟内存大小存在一些限制,这在很大程度上取决于应用程序如何使用其内存空间。这些限制源于操作系统管理虚拟内存的方式效率低下,因为操作系统针对低功耗而非大量文件I / O进行了积极调整。

如果您不关心这些实际限制的细节,请随时停止阅读。否则,接下来是我在研究iOS上的内存问题时的注意事项以及虚拟内存和内存映射文件的入门,以及关于iOS与其他操作系统的不同之处的大量讨论。

什么是虚拟内存?

在现代操作系统(包括iOS)中,您的进程可以访问的所有内存都是技术上的虚拟内存。它被称为"虚拟"内存,因为暴露给进程的地址空间(称为进程的逻辑地址空间)不一定与机器的物理地址空间,甚至是其他进程的虚拟地址空间对齐。虚拟内存允许内核在不同的上下文中提供不同的逻辑地址空间。

在iOS上,此逻辑地址空间的大小理论上仅受指针大小的限制,指针大小由处理器体系结构定义。这意味着进程在32位处理器上具有大约4千兆字节的逻辑内存空间,在64位处理器上具有18艾字节。

但我的设备只有2GiB的RAM,我怎么能实际使用18艾字节的内存空间?

要回答这个问题,首先你必须意识到,当你的进程调用像malloc这样的东西来获得一点内存时,内核会设置你的进程的一部分逻辑地址空间和标记它已分配。在这种情况下,这个分配的内存也占用了物理内存空间。存储在物理内存中的数据称为驻留,因为它驻留在物理内存中,而驻留的数据称为驻留集的一部分。内核通常通过跟踪进程的驻留集大小来计算物理内存使用量与物理内存限制的对比。

如果这是您的进程分配内存的唯一方式,那么对于大多数现代操作系统,您的进程将受到未分配的物理内存量以及计算机页面文件中可用空间量的限制,交换分区或其他一些非易失性后备存储。但是,iOS没有后备存储,并且它会公平地执行strict constraints on the maximum resident set size of a process,因此通常您的应用程序的驻留集大小将受可用物理内存和每个进程驻留集限制中较小者的限制。

因此,如果分配内存并不能让你接近极限,为什么每个进程都需要18艾字节的地址空间?

有用的一个例子是内存映射文件。

如果您的应用程序需要快速访问文件,并且您希望依赖内核来确定要读取的文件的哪些位以及何时读取,则可以对该文件进行内存映射(请参阅{{3}的文档})。在这种情况下,内核将文件(或您请求的文件部分)作为进程逻辑地址空间的连续区域呈现给您的进程。

内存映射文件如何工作?

操作系统将捕获对映射文件保留的逻辑内存空间部分的访问,并在访问时将文件的块透明地复制到物理内存中。这些"块"被称为 pages ,并且允许内核执行此操作的陷阱称为page fault,而使数据驻留的行为在中称为分页,并且从内存中删除页面称为分页。这一切都使你的过程看起来像你已经映射的文件区域(或者整个文件,如果这是你映射的内容)一直在内存中。当然,为了使其运行良好,操作系统必须检测暂时无法访问的页面,并将其分页。

iOS映射文件支持与其他操作系统有何不同?

在上面的场景中,与大多数桌面类操作系统相比,iOS有点受限。具体来说,从我在文档中看到的情况来看,似乎在iOS页面上只能使用PROT_READ标志在只读映射时从物理内存中清除。这意味着,如果您使用PROT_WRITE标记映射文件,则此文件中的页面将保持驻留状态,直到您致电munmap(我无法单独从文档中了解这是否意味着所有页面将保持驻留,或者如果它只是修改过的页面,那么这些页面就会被保留。

此行为与其他操作系统不同,例如PROT_WRITEMAP_SHARED的情况一样,可以随时清除未修改的页面,并且一旦与磁盘同步,可以清除已修改的页面(又名,一旦他们不再"脏")。对于其他操作系统,当使用PROT_WRITEMAP_PRIVATE时,未修改页面的情况保持不变,但只要操作系统正在使用某些操作系统,修改后的页面仍然可以从物理内存中清除。支持商店,"例如页面文件。

在后一种情况下,iOS无法将这些修改分页,因为它没有后备存储。我发现先前的情况令人困惑,因为理论上没有逻辑限制来允许同步页面被分页。我可以推断的最多的是,在PROT_WRITEMAP_SHARED情况下,这些页面保持驻留状态,以避免在SMP环境中I / O调度程序和寻呼机之间需要紧密同步。文档中的弱建议(下面的链接)支持此推断,在OSX上,修改后的页面将被写入后备存储,无论它们是否与磁盘同步。我打算在Mach内核上做更多的阅读,以便更全面地理解这些局限性。

所以带有mmap的{​​{1}}似乎是我们使用所有流程的可用VM空间而不会达到常驻设置大小限制的路径,对吧?我的意思是,使用这种方法,理论上你可以多次创建一些大文件的只读映射,每个映射占用进程的可用逻辑内存空间的一个单独部分。在32位操作系统上,即使在32位iOS上,您也可以很容易地通过虚拟地址空间饱和来实现您经过深思熟虑的世界统治计划。每个人PROT_READ

因此,如果没有任何虚拟内存限制,为什么我的应用程序在映射只读文件时会被杀死?

实际上,虽然在许多操作系统上,您只需ENOMEM一个文件并在操作系统找出详细信息时轻松休息,但iOS的情况并非如此。即使只读映射文件占据了进程的逻辑地址空间,您的应用程序仍可能因为超出驻留设置的内存限制而被杀死。这是因为内核决定哪些页面可以从物理内存中删除。

在阅读下一部分内容时,请记住iOS已针对功效进行了非常积极的调整。它不是文件服务器。

内核只释放被标记为非活动状态的页面,我将从下面链接的文档中推断出,如果页面在某个阈值时间段内未被触摸,则只能被标记为非活动状态。

我还会从文档和我自己的经验推断,负责标记页面不活动的内核部分与负责检查驻留集大小限制的内核部分不能很好地协调。

当您的常驻设置大小接近限制时,操作系统会尝试清除非活动页面,并触发内存警告,应用程序应通过减少其驻留设置大小来响应。一旦您的常驻设置大小超过某个阈值,jetsam就会杀死您的应用。

因此,鉴于上述情况,当您的应用程序在大量页面上进行大量随机访问时,如果内核负责标记页面处于非活动状态,那么会发生什么?

即使您的常驻集合的大部分被只读映射文件页面占用,您的应用也会被终止。

我认为这是苹果建议尽可能使用更小,更多瞬态映射的主要原因之一,而不是映射整个文件(尽管在该使用模式中,内存空间碎片开始成为一个问题)。

这个答案不够荒谬!我要求更多信息!

如果您想了解更多信息,请参阅mmap上的Apple文档,以及virtual memory in iOS and OSXmemory mapped files section of the File System Advanced Programming Topics doc

顺便说一下,还有其他一些值得阅读的相关主题,这使得这一切变得更加复杂和有用,例如页面锁定,页面同步,I / O缓存,预取以及非常好奇,操作系统如何实现对共享映射的高效多处理访问。

答案 1 :(得分:3)

根据此设备上的内存压力测试,iPad Pro(12.9")和运行iOS 10.1.1的4 GiB RAM的上限约为4320-4325 MiB。

请注意,4320 MiB超过总物理内存(4194828288字节== ~4000.5 MiB),但远低于18艾字节。

通过让后台进程逐渐分配越来越多的内存直到收到内存警告来执行测试。根据运行的测试,它将释放该内存并停止,否则忽略警告并继续分配,直到应用程序崩溃。

在观看RM(驻留内存)和VM(虚拟内存)时,结果出乎意料。 RM会在一段时间内增加与VM相同的增量,一次增加1 MiB,然后它会减少一些量(例如-18 MiB)。重复此模式,峰值RM值永远不会超过物理内存总量。

摘自一次碰撞测试:

VM: 4477714432 (4270 MiB), VM diff: 1048576 (1 MiB), RM: 1354809344 (1292 MiB), RM diff: 1048576 (1 MiB)
VM: 4478763008 (4271 MiB), VM diff: 1048576 (1 MiB), RM: 1355857920 (1293 MiB), RM diff: 1048576 (1 MiB)
VM: 4479811584 (4272 MiB), VM diff: 1048576 (1 MiB), RM: 1356906496 (1294 MiB), RM diff: 1048576 (1 MiB)
VM: 4480860160 (4273 MiB), VM diff: 1048576 (1 MiB), RM: 1357955072 (1295 MiB), RM diff: 1048576 (1 MiB)
VM: 4481908736 (4274 MiB), VM diff: 1048576 (1 MiB), RM: 1359003648 (1296 MiB), RM diff: 1048576 (1 MiB)
VM: 4482957312 (4275 MiB), VM diff: 1048576 (1 MiB), RM: 1360052224 (1297 MiB), RM diff: 1048576 (1 MiB)
VM: 4484005888 (4276 MiB), VM diff: 1048576 (1 MiB), RM: 1361100800 (1298 MiB), RM diff: 1048576 (1 MiB)
VM: 4485054464 (4277 MiB), VM diff: 1048576 (1 MiB), RM: 1344323584 (1282 MiB), RM diff: -16777216 (-16 MiB)
VM: 4486103040 (4278 MiB), VM diff: 1048576 (1 MiB), RM: 1345372160 (1283 MiB), RM diff: 1048576 (1 MiB)
VM: 4487151616 (4279 MiB), VM diff: 1048576 (1 MiB), RM: 1346420736 (1284 MiB), RM diff: 1048576 (1 MiB)
VM: 4488200192 (4280 MiB), VM diff: 1048576 (1 MiB), RM: 1347469312 (1285 MiB), RM diff: 1048576 (1 MiB)
VM: 4489248768 (4281 MiB), VM diff: 1048576 (1 MiB), RM: 1348517888 (1286 MiB), RM diff: 1048576 (1 MiB)
VM: 4490297344 (4282 MiB), VM diff: 1048576 (1 MiB), RM: 1349566464 (1287 MiB), RM diff: 1048576 (1 MiB)
VM: 4491345920 (4283 MiB), VM diff: 1048576 (1 MiB), RM: 1350615040 (1288 MiB), RM diff: 1048576 (1 MiB)
VM: 4492394496 (4284 MiB), VM diff: 1048576 (1 MiB), RM: 1351663616 (1289 MiB), RM diff: 1048576 (1 MiB)
VM: 4493443072 (4285 MiB), VM diff: 1048576 (1 MiB), RM: 1352712192 (1290 MiB), RM diff: 1048576 (1 MiB)
VM: 4494491648 (4286 MiB), VM diff: 1048576 (1 MiB), RM: 1353760768 (1291 MiB), RM diff: 1048576 (1 MiB)
VM: 4495540224 (4287 MiB), VM diff: 1048576 (1 MiB), RM: 1354809344 (1292 MiB), RM diff: 1048576 (1 MiB)
VM: 4496588800 (4288 MiB), VM diff: 1048576 (1 MiB), RM: 1355857920 (1293 MiB), RM diff: 1048576 (1 MiB)
VM: 4497637376 (4289 MiB), VM diff: 1048576 (1 MiB), RM: 1356906496 (1294 MiB), RM diff: 1048576 (1 MiB)
VM: 4498685952 (4290 MiB), VM diff: 1048576 (1 MiB), RM: 1357955072 (1295 MiB), RM diff: 1048576 (1 MiB)
VM: 4499734528 (4291 MiB), VM diff: 1048576 (1 MiB), RM: 1359003648 (1296 MiB), RM diff: 1048576 (1 MiB)
VM: 4500783104 (4292 MiB), VM diff: 1048576 (1 MiB), RM: 1360052224 (1297 MiB), RM diff: 1048576 (1 MiB)
VM: 4501831680 (4293 MiB), VM diff: 1048576 (1 MiB), RM: 1361100800 (1298 MiB), RM diff: 1048576 (1 MiB)
VM: 4502880256 (4294 MiB), VM diff: 1048576 (1 MiB), RM: 1362149376 (1299 MiB), RM diff: 1048576 (1 MiB)
VM: 4503928832 (4295 MiB), VM diff: 1048576 (1 MiB), RM: 1363197952 (1300 MiB), RM diff: 1048576 (1 MiB)
VM: 4504977408 (4296 MiB), VM diff: 1048576 (1 MiB), RM: 1347469312 (1285 MiB), RM diff: -15728640 (-15 MiB)
VM: 4506025984 (4297 MiB), VM diff: 1048576 (1 MiB), RM: 1348517888 (1286 MiB), RM diff: 1048576 (1 MiB)
VM: 4507074560 (4298 MiB), VM diff: 1048576 (1 MiB), RM: 1349566464 (1287 MiB), RM diff: 1048576 (1 MiB)
VM: 4508123136 (4299 MiB), VM diff: 1048576 (1 MiB), RM: 1350631424 (1288 MiB), RM diff: 1064960 (1 MiB)
VM: 4509171712 (4300 MiB), VM diff: 1048576 (1 MiB), RM: 1351680000 (1289 MiB), RM diff: 1048576 (1 MiB)
VM: 4510220288 (4301 MiB), VM diff: 1048576 (1 MiB), RM: 1352728576 (1290 MiB), RM diff: 1048576 (1 MiB)
VM: 4511268864 (4302 MiB), VM diff: 1048576 (1 MiB), RM: 1353777152 (1291 MiB), RM diff: 1048576 (1 MiB)
VM: 4512317440 (4303 MiB), VM diff: 1048576 (1 MiB), RM: 1354825728 (1292 MiB), RM diff: 1048576 (1 MiB)
VM: 4513366016 (4304 MiB), VM diff: 1048576 (1 MiB), RM: 1355874304 (1293 MiB), RM diff: 1048576 (1 MiB)
VM: 4514414592 (4305 MiB), VM diff: 1048576 (1 MiB), RM: 1356922880 (1294 MiB), RM diff: 1048576 (1 MiB)
VM: 4515463168 (4306 MiB), VM diff: 1048576 (1 MiB), RM: 1357971456 (1295 MiB), RM diff: 1048576 (1 MiB)
VM: 4516511744 (4307 MiB), VM diff: 1048576 (1 MiB), RM: 1359020032 (1296 MiB), RM diff: 1048576 (1 MiB)
VM: 4517560320 (4308 MiB), VM diff: 1048576 (1 MiB), RM: 1360068608 (1297 MiB), RM diff: 1048576 (1 MiB)
VM: 4518608896 (4309 MiB), VM diff: 1048576 (1 MiB), RM: 1361117184 (1298 MiB), RM diff: 1048576 (1 MiB)
VM: 4519657472 (4310 MiB), VM diff: 1048576 (1 MiB), RM: 1362165760 (1299 MiB), RM diff: 1048576 (1 MiB)
VM: 4520706048 (4311 MiB), VM diff: 1048576 (1 MiB), RM: 1363214336 (1300 MiB), RM diff: 1048576 (1 MiB)
VM: 4521754624 (4312 MiB), VM diff: 1048576 (1 MiB), RM: 1364262912 (1301 MiB), RM diff: 1048576 (1 MiB)
VM: 4522803200 (4313 MiB), VM diff: 1048576 (1 MiB), RM: 1365311488 (1302 MiB), RM diff: 1048576 (1 MiB)
VM: 4523851776 (4314 MiB), VM diff: 1048576 (1 MiB), RM: 1366360064 (1303 MiB), RM diff: 1048576 (1 MiB)
VM: 4524900352 (4315 MiB), VM diff: 1048576 (1 MiB), RM: 1367408640 (1304 MiB), RM diff: 1048576 (1 MiB)
VM: 4525948928 (4316 MiB), VM diff: 1048576 (1 MiB), RM: 1347715072 (1285 MiB), RM diff: -19693568 (-18 MiB)
VM: 4526997504 (4317 MiB), VM diff: 1048576 (1 MiB), RM: 1348616192 (1286 MiB), RM diff: 901120 (0 MiB)
VM: 4528046080 (4318 MiB), VM diff: 1048576 (1 MiB), RM: 1349664768 (1287 MiB), RM diff: 1048576 (1 MiB)
VM: 4529094656 (4319 MiB), VM diff: 1048576 (1 MiB), RM: 1350713344 (1288 MiB), RM diff: 1048576 (1 MiB)
VM: 4530143232 (4320 MiB), VM diff: 1048576 (1 MiB), RM: 1351761920 (1289 MiB), RM diff: 1048576 (1 MiB)
VM: 4531191808 (4321 MiB), VM diff: 1048576 (1 MiB), RM: 1352810496 (1290 MiB), RM diff: 1048576 (1 MiB)
Message from debugger: Terminated due to memory issue

这种行为看起来很像VM交换给我。

更新:作为实验,执行修改后的测试,注释掉memset,以便分配内存但不填充任何值。
- >内存压力测试从未收到警告并在VM崩溃:8979611648(8563 MiB),RM:194134016(185.1 MiB)

maia(2943,0x256573000) malloc: *** mach_vm_map(size=10485760) failed (error code=3) *** error: can't allocate region