【问题标题】: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系统调用。

      缺点是您必须使用writeread 而不是fwritefread,它们不会做缓冲之类的事情(这一切都在您的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
      相关资源
      最近更新 更多