【问题标题】:Programmatically free up system memory using Objective-C使用 Objective-C 以编程方式释放系统内存
【发布时间】:2012-08-29 22:33:37
【问题描述】:

所以,这就是我想要做的:

  • 释放系统内存(非活动内存),与purge 命令的方式相同,但以编程方式。

我已经尝试过这里的代码(它的作者声称它可以工作),但它所做的只是导致 Mac OS X 冻结:

void
free_up_memory()
{
    int c;
    char *p, *q;

    for(c = 0; c < 2048; c++)
    {
        if(!(p = malloc(1024 * 1024)))
        {

            return;
        }
        for(q = p; q < p + (1024 * 1024); q += 4096)
        {
            *q = 1;
        }

    }
}

有什么想法吗?

【问题讨论】:

  • 链接到“它的作者”,解释一下可能好吗?
  • 哦,你为什么要释放内存——如果它处于非活动状态,OSX 不会在你请求时给你它(这不是一个尖刻的评论,我真的很感兴趣: )

标签: objective-c c macos cocoa memory


【解决方案1】:

现实情况是,代码没有做——也永远不会做——它声称的事情。太垃圾了。

它要做的就是破坏系统的缓冲区缓存子系统,并可能使机器快速分页,从而导致看起来完全像锁定的症状。尤其是在具有慢速(例如 5,400 转笔记本电脑驱动器)硬盘驱动器的系统上。

至少,在 RAM 相对较少的系统上。在具有大量 RAM 和运行的应用程序负载相对较轻的系统上,该程序将驱逐 2GB 的缓冲区缓存,导致各种 I/O 操作变慢,因为需要从磁盘重新读取各种内容,而不是真的帮助任何事情。

也不应该有任何这样的事情;如果应用程序需要内存,系统会根据需要从缓冲区缓存中逐出页面和/或将内存分页到磁盘(在 OS X 上 - 在 iOS 上,没有分页器能够写入脏页以保持响应能力)。

调用purge 将驱逐各种磁盘缓冲区缓存并模拟冷启动时的情况,但是 - 再次 - 这只会破坏系统的缓存机制,而不会真正提高用户级应用程序的性能。正如手册页文档所述,它对于在 冷缓存 状态下测试应用程序性能非常有用,但即使这样也有点可疑,因为 purge 不会驱逐所有可以被驱逐的东西;不会干净地模拟冷状态。

Steve Jessep 说得很有道理,在某些情况下,调用purge(或类似的)可能会提高这种情况下的性能。这通常 - 几乎普遍 - 在一般情况下分崩离析,因为用户进程 A 无法知道用户进程 B、C、D、....、Z 在附近或遥远的未来。例子; A 可能会去清除东西,只是让 RSS Feed Scraper R 撕下几 MB 的 XML 进行解析和持久化,立即使清除无效。更糟糕的是,R 的最后一次刷新可能仍有一些位潜伏在缓存中,因此 R 的刷新会影响 I/O,使其速度变慢且成本更高(包括消耗电池寿命)。

【讨论】:

  • 我知道操作系统应该智能地处理非活动内存,但我一次又一次地看到,当内存使用率接近 100% 时,即使有几千兆字节,系统也会缓慢爬行的非活动记忆。 10.7 和 10.8 似乎不能很好地处理这种情况。运行 purge 会进一步减慢它的速度,但一旦 purge 退出,系统会立即恢复到全速。 10.9 以前的版本似乎处理得更好,这可能是由于内存压缩功能。
  • 为什么操作系统在具有千兆字节非活动内存的低内存情况下如此困难?非活动 RAM 只是磁盘中的内容缓存,不是吗?它不应该能够几乎立即释放内存吗?也许我应该把它作为一个问题而不是评论发布。
【解决方案2】:

这段代码实际所做的是将尽可能多的内存分配到 1MB 块中,最多可达 2GB,并向其中写入一些数据以确保实际提交内存。也就是说,要确保您不仅分配了虚拟地址空间,而且没有分配内存。然后它会泄漏它。

因此,代码所做的是“强制操作系统在内存不足时执行其操作”。然后当这个程序退出时,它的内存被释放,你有很多不错的可用空间。

此代码的作者希望“操作系统在内存不足时执行的操作”是释放您所谓的“非活动内存”。看起来它实际上为你做的是冻结。显然这是一个错误。任何时候都有任意数量的设备和服务在运行,只有其中一个有缺陷才会导致问题。对于操作系统冻结,问题必须是在高于用户模式下运行的东西,所以我很失望但并不感到惊讶。

【讨论】:

  • 我怀疑系统正在冻结。它很可能在交换死亡中,分页出太多的内存,以至于磁盘 I/O 使它看起来像是被楔入的。与内存相比,磁盘非常慢。但总的来说,OP 所做的只是浪费时间。
  • @bbum:我说的是提问者的话,系统正在冻结。如果不是,他们可以问另一个问题;-) 但是,如果它在(比如说)3 小时后没有移动,那么即使磁盘显示活动,我也可能会称它为已冻结,因为这比它应该花费的时间要长得多将 2GB 的数据铲入和移出交换几次。
  • 是的——但是,最终,我们正在讨论一堆垃圾的优点。该代码不会做OP想要的。在调试环境中调用purge 可能会很有趣,以查看您的应用程序的行为方式,但这对系统来说也是一件卑鄙的事情,因为当用户级代码不尝试时,系统级缓存工作得最好第二次猜他们。
  • @bbum:我发现提倡清除的人实际上是相反的——非常不受控制的环境,但他们发现在运行了一些资源占用应用程序的组合(针对不同人的不同应用程序)后,OSX 得到了本身进入一种缓慢的状态,清除似乎可以解决。其中一位特别表示,在退出应用程序之后,OSX 将一直无法运行声称内存不足的东西,直到它们运行 purge。对我来说,这是另一个“失望但并不完全惊讶”的案例。不在海湾地区,但如果你曾经在英国牛津,请大喊大叫。我们的品脱更大!
  • 当然有可能 purge 没有解决它,但是坐了几分钟等待 purge 确实解决了它,他们夸大了他们认为已经解决的原始问题 :-)
【解决方案3】:

Mac OS X 可能会冻结,因为它正在等待虚拟内存管理器 (VMM) 将页面换出到磁盘;由于您的函数正在快速分配内存,因此系统正在尽其所能为其提供服务,并且它将在放弃之前使用磁盘交换文件。

一旦发生这种情况,系统中分配内存的所有内容都将停止,而 VMM 正在换入和换出页面。通常这只会在各处造成小的延迟,但由于您正在消耗所有可用内存,因此几乎系统中的所有内容都会在磁盘 I/O 上阻塞。

我相当有信心,如果您等待的时间足够长,VMM 会赶上来,系统会恢复正常。

您可以通过在应用运行时查看活动监视器来测试我的假设;如果我是对的,Mac 冻结时磁盘 I/O 会非常高。

如果你真的想释放内存,你应该做一些不同的事情:以编程方式执行purge 命令,或者将malloc 的调用替换为保持内存“连线”的东西(不会被分页到磁盘)。或者,根本不这样做,与其事后猜测 VMM,不如让它完成它的工作。

【讨论】:

  • 通过在外循环中引入sleep 来测试这个理论——如果问题是交换交换而不是内存不足,那么慢慢运行相同的代码就可以了。
【解决方案4】:

该程序的执行方式与purge 不同——它只是试图模拟purge 的效果。有时这是成功的,有时它只是将不必要的内存量刷新到磁盘(这可以解释为什么当您返回它们时您的程序可能会很慢)。 purge 做了完全不同的事情——它专注于特定的内存。

就“冻结”而言,是的,一旦达到上限,系统就会开始将内存内容推送到磁盘。系统还将尝试在进程中释放内存支持的文件节点——内存支持的文件节点具体是purge 所关注的。您的程序最终会将其他进程的内存推送到磁盘。这不是解决问题的好方法。它要求太多,而且没有选择性。无论如何……这种方法可以像宣传的那样有效。它做一些类似的事情,并且可以在这个过程中释放磁盘缓冲区缓存。

FWIW,这在 10.8 中的问题比 10.7 小。

【讨论】:

  • purge 也不会导致交换死亡(尽管随着缓存缓冲区的重新填充,它会导致大量读取 I/O)。
  • @bbum 对。 purge 可能会导致系统在驱逐(+恢复)期间出现一段时间的迟缓 - 蛮力驱逐技术(在 OP 中)可能会使系统在几分钟内无法使用,具体取决于可用内存和被分页的内容(+更长的时间恢复)。
【解决方案5】:

这应该会释放 OS X 认为不需要的所有 RAM:

-(void)purgeRAM {
    NSTask *purgeTask = [[NSTask alloc] init];
    [purgeTask setLaunchPath:@"/usr/bin/purge"];
    [purgeTask launch];
    [purgeTask waitUntilExit];
    NSLog(@"Purge complete");
}

【讨论】:

  • 我试过了,我发现异常启动路径不可访问
  • 启动路径不可访问
  • 请注意,答案来自 2013 年,当我有一台 Mac 时,它并没有运行今天发布的最新最好的 OS X。
  • 对于未来的读者,purge 在更高的 macOS 版本中位于 /usr/sbin => which purge => /usr/sbin/purge
猜你喜欢
  • 2014-05-18
  • 1970-01-01
  • 1970-01-01
  • 2011-02-20
  • 2015-08-06
  • 1970-01-01
  • 2011-10-12
  • 2019-01-30
  • 1970-01-01
相关资源
最近更新 更多