【问题标题】:How to increase the limit of "maximum open files" in C on Mac OS X如何在 Mac OS X 上增加 C 中“最大打开文件数”的限制
【发布时间】:2011-03-11 03:43:21
【问题描述】:

Mac OS X 上最大打开文件的默认限制是 256 (ulimit -n),我的应用程序需要大约 400 个文件处理程序。

我尝试使用 setrlimit() 更改限制,但即使函数执行正确,我仍然限制为 256。

这是我使用的测试程序:

#include <stdio.h>
#include <sys/resource.h>

main()
{
  struct rlimit rlp;

  FILE *fp[10000];
  int i;

  getrlimit(RLIMIT_NOFILE, &rlp);
  printf("before %d %d\n", rlp.rlim_cur, rlp.rlim_max);

  rlp.rlim_cur = 10000;
  setrlimit(RLIMIT_NOFILE, &rlp);

  getrlimit(RLIMIT_NOFILE, &rlp);
  printf("after %d %d\n", rlp.rlim_cur, rlp.rlim_max);

  for(i=0;i<10000;i++) {
    fp[i] = fopen("a.out", "r");
    if(fp[i]==0) { printf("failed after %d\n", i); break; }
  }

}

输出是:

before 256 -1
after 10000 -1
failed after 253

我不能要求使用我的应用程序的人在 /etc 文件或其他内容中进行操作。我需要应用程序自行完成。

【问题讨论】:

  • 为什么需要同时打开这么多文件?
  • 没关系,但您是在服务器版还是 OSX 的桌面版上进行测试?我可以想象苹果人决定限制桌面应用程序可以打开多少文件,因为打开很多文件通常是面向服务器的任务......

标签: c macos system ulimit


【解决方案1】:

Mac OS 不允许我们像许多基于 unix 的操作系统那样轻松更改限制。我们必须创建两个文件

/Library/LaunchDaemons/limit.maxfiles.plist /Library/LaunchDaemons/limit.maxproc.plist 描述最大过程和最大文件限制。文件的所有权需要更改为 'root:wheel'

仅此一项并不能解决问题,默认情况下,最新版本的 mac OSX 使用 'csrutil',我们需要禁用它。要禁用它,我们需要在恢复模式下重新启动我们的 mac,然后使用终端禁用 csrutil。

现在我们可以轻松地从终端本身更改最大打开文件句柄限制(即使在正常启动模式下)。

此方法在以下链接中有详细说明。 http://blog.dekstroza.io/ulimit-shenanigans-on-osx-el-capitan/

适用于 OSX-elcapitan 和 OSX-Seirra。

【讨论】:

  • OP 询问如何在 C 语言中以编程方式执行此操作,而不是在用户级别。
【解决方案2】:

出于某种原因(可能是二进制兼容性),您必须在包含&lt;stdio.h&gt; 之前定义_DARWIN_UNLIMITED_STREAMS:

#define _DARWIN_UNLIMITED_STREAMS

#include <stdio.h>
#include <sys/resource.h>

main()
{
  struct rlimit rlp;

  FILE *fp[10000];
  int i;

  getrlimit(RLIMIT_NOFILE, &rlp);
  printf("before %d %d\n", rlp.rlim_cur, rlp.rlim_max);

  rlp.rlim_cur = 10000;
  setrlimit(RLIMIT_NOFILE, &rlp);

  getrlimit(RLIMIT_NOFILE, &rlp);
  printf("after %d %d\n", rlp.rlim_cur, rlp.rlim_max);

  for(i=0;i<10000;i++) {
    fp[i] = fopen("a.out", "r");
    if(fp[i]==0) { printf("failed after %d\n", i); break; }
  }

}

打印

before 256 -1
after 10000 -1
failed after 9997

此功能似乎已在 Mac OS X 10.6 中引入。

【讨论】:

    【解决方案3】:

    etresoft 在apple discussion board 上找到了答案:

    这里的全部问题是你的 printf() 函数。你打电话的时候 printf(),你正在初始化 内部数据结构 尺寸。然后,您调用 setrlimit() 来 尝试调整这些尺寸。那 功能失败,因为你有 已经在使用那些内部 使用您的 printf() 构建结构。如果你 使用两个 rlimit 结构(一个用于 之前和之后),不要 打印它们直到调用之后 setrlimit,你会发现可以 改变当前的限制 甚至在命令行中处理 程序。最大值为 10240。

    【讨论】:

      【解决方案4】:

      rlp.rlim_cur = 10000;

      两件事。

      第一。哈哈。显然您在 Mac OS X 的 stdio 中发现了一个错误。如果我修复您的程序/添加错误处理/等并将 fopen() 替换为 open() 系统调用,我可以轻松达到 10000 的限制(比我的 10.6.3' OPEN_MAX 限制 10240 低 240 fds)

      第二。实时调频:man setrlimit。必须针对 OPEN_MAX 专门处理最大打开文件的情况。

      【讨论】:

      • 谢谢你的答案。当您说这可能是 mac os x 上的 stdio 中的错误或开玩笑时,您是认真的吗?所以唯一的解决方案是使用系统调用而不是标准的 C 函数?
      • @acemtp:限制可能是一个更好的词。标准只要求libc保证一次可以打开8个文件(包括stdin/stdout/stderr!)。这将是一个不寻常的限制,但并非闻所未闻。
      • @acetemp, @evan:Linux 上的 stdio 可以毫无问题地处理我扔给它的任何东西。我个人认为这是一个错误。一次8个文件?? stdio、stdin、stderr - 3 已经很忙了。应用程序日志文件 + 跟踪文件 - 只剩下 3 个可用...如果你问我,这很愚蠢和一个错误。
      【解决方案5】:

      这可能是您的 libc 的硬性限制。某些版本的 solaris 具有类似的限制,因为它们将 fd 作为 unsigned char 存储在 FILE 结构中。如果你的 libc 也是这种情况,你可能无法做你想做的事。

      据我所知,setrlimit 之类的内容只会影响您可以使用 open 打开多少文件(fopen 几乎可以肯定是在 open 上实现的)。因此,如果此限制在 libc 级别,您将需要一个替代解决方案。

      当然,您总是不能使用fopen,而是使用几乎所有unix变体都可用的open系统调用。

      缺点是您必须使用write 和read 而不是fwrite 和fread,它们不会做缓冲之类的事情(这一切都在您的libc 中完成,而不是由操作系统本身完成) .所以它最终可能会成为性能瓶颈。

      您能否描述需要同时打开 ** 400 个文件** 的场景?我并不是说没有必要这样做。但是,如果您更清楚地描述您的用例,那么也许我们可以推荐一个更好的解决方案。

      【讨论】:

      • libc 限制:是的。看我的评论。将程序更改为使用 open() 而不是 fopen() 可以解决问题。在 Linux 上 btw 就像一个魅力 - 在用 rlp.rlim_max 替换 10000 的明显修复之后(但在 Mac OS X 上,即使是不同的,因为也必须检查 OPEN_MAX 的上限)。您需要 400 个 fds 的场景……我维护专门的网络服务器,它也将数据备份到磁盘。看到 2K 套接字和正在使用的打开文件并不少见。
      • @Dummy00001:好的,这当然是 a 场景,但是让acemtp 准确描述他正在尝试做的事情仍然可以提供帮助:-P。但看起来我们已经找到了问题的本质。
      【解决方案6】:

      我知道这听起来是个愚蠢的问题,但您真的需要同时打开 400 个文件吗? 顺便问一下,你是在以 root 身份运行这段代码吗?

      【讨论】:

      • 是的,我需要同时打开 400 个文件,但我不是 root。正如男人所说,因为我没有更改最大限制,而只是更改当前限制,所以我不必成为 root。
      • 但是 max limit 不是 cur 限制吗?
      猜你喜欢
      • 1970-01-01
      • 2014-02-26
      • 1970-01-01
      • 2015-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多