文件描述符限制和默认堆栈大小

时间:2010-02-27 06:52:59

标签: c

在我工作的地方,我们构建并分发了一个库和一些基于该库构建的复杂程序。所有代码都是用C语言编写的,并且可以在大多数“标准”系统上使用,如Windows,Linux,Aix,Solaris,Darwin。

我从QA部门开始,在最近运行测试时,我已经多次提醒我需要记住设置文件描述符限制和默认堆栈大小更高或坏事情将发生。对于Solaris和现在的Darwin来说尤其如此。

现在这对我来说非常奇怪,因为我是一个相信0所需的环境,摆弄产品。所以我想知道是否有时候这种要求是必要的邪恶,或者我们做错了什么。

编辑:

描述问题和一些背景的好评。但是我不相信我的问题已经说得好。目前,我们要求客户以及测试人员在运行我们的代码之前设置这些限制。我们不是以编程方式执行此操作。并且这不是他们可能用完的情况,在正常负载下我们的程序会耗尽并且出现故障。 重新提出问题,是要求客户更改这些ulimit值以在某些平台上运行我们的软件,例如Solaris,Aix,还是我们作为一家公司让这些用户难以开始?

奖励: 我添加了一笔赏金,希望能够获得更多有关其他公司正在采取哪些措施来管理这些限制的信息。你能用实际设置吗?我们应该吗?我们的计划是否应该达到这些限制,或者这可能是一个迹象表明事情可能有点凌乱?这真的是我想要知道的,作为一个完美主义者,一个看似肮脏的程序真的让我烦恼。

7 个答案:

答案 0 :(得分:7)

如果您需要更改这些值以使QA测试运行,那么这不是太大的问题。但是,要求客户执行此操作以便程序运行应避免(恕我直言)。如果不出意外,请创建一个包装器脚本来设置这些值并启动应用程序,以便用户仍然可以单击一次启动应用程序。但是,从程序中设置这些将是更好的方法。至少,如果限制太低,程序会在启动时检查限制并且(干净地)错误地提前输出。

如果软件开发人员告诉我,我必须弄乱我的堆栈和描述符限制才能运行程序,这会改变我对软件的看法。这会让我想知道“为什么他们需要超出我所拥有的其他软件显然可以接受的系统限制?”。这可能是也可能不是一个有效的问题,但被要求做一些(对许多人来说)似乎是hackish的事情与你刚刚发起和去的程序没有相同的专业优势。

当你说“这不是他们可能用完的情况时,这个问题似乎更糟,在正常负载下我们的程序会耗尽并且出现故障”。超出这些限制的程序是一回事,但是一个不能优雅地处理因超出这些限制而导致的错误条件的程序则是另一回事。如果您达到文件句柄限制并尝试打开文件,则应该收到错误消息,指示您打开了太多文件。这不应该导致程序设计良好的程序崩溃。检测堆栈使用问题可能更困难,但是文件描述符的耗尽不应该导致崩溃。

您没有详细说明这是什么类型的程序,但我认为假设您的程序用户必须具有足够的权限来更改这些值是不安全的。在任何情况下,假设在程序运行时没有其他任何东西可能会在用户不知情的情况下改变这些值,这可能也是不安全的。

虽然总有例外,但我会说,一般来说,超出这些限制的程序需要重新检查其代码。限制是有原因的,并且系统中的几乎所有其他软件都在这些限制范围内工作而没有任何问题。您是否真的需要同时打开多个文件,或者打开一些文件,处理它们,关闭它们还打开更多文件会更清晰吗?你的图书馆/程序试图在一个大包中做太多,或者将它分解成一起工作的较小的独立部分会更好吗?您是否超出了堆栈限制,因为您正在使用可以以非递归方式重写的深度递归算法?可能有很多方法可以改进有问题的库和程序,以便减少更改系统资源限制的需要。

答案 1 :(得分:1)

在Darwin上,打开文件数的默认软限制为256;默认的硬限制是无限制的。

AFAICR,在Solaris上,打开文件数量的默认软限制为16384,硬限制为32768。

对于堆栈大小,Darwin的软/硬限制为8192/65536 KB。我忘记了Solaris上的限制(我的Solaris机器不可用 - 纽约州Poughkeepsie的停电意味着我无法通过VPN从我在加利福尼亚州的家中访问堪萨斯州的机器),但它非常重要。 / p>

我不担心硬限制。如果我认为库可能会用完256个文件描述符,我会增加达尔文的软限制;我可能不会在Solaris上烦恼。

类似的限制适用于Linux和AIX。我不能回答Windows。

悲伤的故事:几年前,我删除了改变程序中最大文件大小限制的代码 - 因为它从2 MB是一个大文件的日子里没有改变(而且有些系统有软文件)限制只有0.5 MB)。十年前和一些前,它实际上增加了限制;当它被删除时,它很烦人,因为它减少了限制。 Tempus fugit等等。


在SuSE Linux(SLES 10)上,打开文件限制为4096/4096,堆栈限制为8192 /无限制。

答案 2 :(得分:1)

简短的回答是:这是正常的,但并非不灵活。当然,限制措施是为了防止恶意流程或用户使资源系统匮乏。桌面系统的限制性要小于服务器系统,但仍有一定的限制(例如文件句柄)。

这并不是说用户可以自行决定(例如,通过在ulimit中添加相关的.profile电话)或以编程方式从内部进行持久/可再现方式更改限制程序/库,确信他们需要大量的文件句柄(例如setsysinfo(SSI_FD_NEWMAX,...)),堆栈(在pthread创建时提供)等等。

答案 3 :(得分:1)

由于您必须支持大量不同的系统,我认为设置某些已知为系统限制/资源的良好值是明智的,因为系统之间的默认值可能会有很大差异。

pthread堆栈的默认大小是例如这种情况。我最近不得不发现HPUX11.31的默认值是256KB(!),这对我们的应用程序来说不是很合理。

设置明确定义的值可以提高应用程序的可移植性,因为您可以确保在每个平台上都有X个文件描述符,堆栈大小为Y,...并且事情不仅仅是好运。< / p>

我倾向于从程序本身设置这样的限制,因为用户有更少的事情搞砸(有人总是试图在没有包装器脚本的情况下运行二进制文件)。要选择允许运行时自定义,可以使用环境变量覆盖默认值(仍然强制执行最小限制)。

答案 4 :(得分:1)

让我们这样看待它。要求客户设置这些限制并不是非常客户友好。正如其他答案中详述的那样,您最有可能达到软限制并且可以更改这些限制。因此,如果有必要,可以在启动实际应用程序的脚本中自动更改它们(如果硬限制太低而产生错误消息而不是段错误,您甚至可以编写它以使其失败)。

这是它的实际部分。在不知道应用程序是什么的情况下,我有点猜测,但在大多数情况下,您不应该接近达到(甚至不太渐进的)操作系统的任何默认限制。假设系统不是受请求轰炸的服务器(因此使用了大量的文件/套接字句柄),这可能是编程草率的一个标志。根据程序员的经验,我猜想文件描述符对于只读/写一次的文件是开放的,或者系统在只偶尔更改/读取的文件上保持打开文件描述符。

关于堆栈大小,这可能意味着两件事。程序耗尽堆栈的标准原因是过度递归(或无限递归),这是一个错误条件,实际上这些限制旨在解决。第二件事是在堆栈上分配了一些大的(可能是配置)结构,应该在堆内存中分配。它甚至可能更糟糕,那些巨大的结构正在通过值(而不是引用)传递,这意味着可用(浪费)堆栈空间的大量打击以及大的性能损失。

答案 5 :(得分:0)

小提示:如果您计划通过64位处理器运行应用程序,请注意无限制地设置stacksize。在64位Linux系统中,将-1作为stacksize给出。

由于 希亚姆

答案 6 :(得分:0)

也许您可以添加适合启动脚本的任何内容,例如'ulimit -n -S 4096'。

但是从2.6开始使用Solaris,在/ etc / system中永久修改rlim_fd_cur和rlim_fd_max并不罕见。在旧版本的Solaris中,它们对于某些工作负载来说太低了,比如运行Web服务器。