如何在Mac OS X上增加C中“最大打开文件”的限制

时间:2010-07-02 14:53:28

标签: c macos system ulimit

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文件或其他内容中查找。我需要应用程序自己完成它。

6 个答案:

答案 0 :(得分:5)

  

rlp.rlim_cur = 10000;

两件事。

第一。大声笑。显然你在Mac OS X'stdio中发现了一个错误。如果我修改你的程序/添加错误处理/等,并用open()系统调用替换fopen(),我可以很容易地达到10000的限制(比我的10.6.3'OPEN_MAX限制10240低240 fds)

第二。 RTFM:man setrlimit。必须特别针对OPEN_MAX处理最大打开文件的情况。

答案 1 :(得分:5)

etresoft在apple discussion board上找到答案:

  

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

答案 2 :(得分:2)

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

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

当然,您始终无法使用fopen,而是使用几乎所有unix版本上的open系统调用。

缺点是您必须使用writeread而不是fwritefread,这些都不会执行缓冲等操作(这些都是在您的libc,而不是操作系统本身)。所以它最终可能成为性能瓶颈。

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

答案 3 :(得分:2)

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

#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中引入。

答案 4 :(得分:0)

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

答案 5 :(得分:-1)

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

/Library/LaunchDaemons/limit.maxfiles.plist /Library/LaunchDaemons/limit.maxproc.plist 描述最大proc和max文件限制。文件的所有权需要更改为&#39; root:wheel&#39;

仅此一项并不能解决问题,默认情况下,最新版本的mac OSX使用&#csrutil&#39;,我们需要禁用它。要禁用它,我们需要在恢复模式下重启我们的mac,并从那里使用终端禁用csrutil。

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

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

适用于OSX-elcapitan和OSX-Seirra。