11

先决条件

POSIX.1 2008 指定setrlimit()getrlimit()函数。为参数提供了各种常量resource,其中一些在下面复制以便更容易理解我的问题。

定义了以下资源:

(...)

RLIMIT_DATA

这是进程的数据段的最大大小,以字节为单位。如果超出此限制,malloc() 函数将失败,并且 errno 设置为 [ENOMEM]。

(...)

RLIMIT_STACK

这是初始线程堆栈的最大大小,以字节为单位。该实现不会自动将堆栈增长到超出此限制。如果超过此限制,则应为线程生成 SIGSEGV。如果线程阻塞 SIGSEGV,或者进程忽略或捕获 SIGSEGV 并且没有安排使用备用堆栈,则 SIGSEGV 的处置应在生成之前设置为 SIG_DFL。

RLIMIT_AS

这是进程的总可用内存的最大大小,以字节为单位。如果超出此限制,malloc() 和 mmap() 函数将失败,并且 errno 设置为 [ENOMEM]。此外,自动堆栈增长会因上述影响而失败。

此外,POSIX.1 2008定义的 数据段如下:

3.125 数据段

与进程关联的内存,可以包含动态分配的数据。

我了解该RLMIT_DATA资源传统上用于表示可以分配给具有该brk()功能的进程的最大内存量。POSIX.1 的最新版本不再指定此函数,并且许多操作系统(例如 Mac OS X)不支持将此函数作为系统调用。mmap()相反,它使用不属于 POSIX.1 2008的变体进行模拟。

问题

我对资源的语义和使用有点困惑RLIMIT_DATA。以下是我的具体问题:

  • 根据此规范,堆栈可以成为数据段的一部分吗?

  • 该标准说RLIMIT_DATA:“如果超出此限制,则 malloc() 函数将失败,并且 errno 设置为 [ENOMEM]。” 这是否意味着分配的内存malloc()必须是数据段的一部分?

    在 Linux 上,分配的内存mmap()不计入数据段。只有分配有brk()或的内存sbrk()是数据段的一部分。最新版本的 glibc 使用一种malloc()实现,它使用mmap(). 因此, 的值RLIMIT_DATA不会影响您可以使用 的此实现分配的内存量malloc()

  • 这是否违反了 POSIX.1 2008?

  • 其他平台是否表现出类似的行为?

    该标准说RLIMIT_AS:“如果超出此限制,则 malloc() 和 mmap() 函数将失败,并且 errno 设置为 [ENOMEM]。” 由于没有mmap()为 指定失败RLIMIT_DATA,我得出结论,从中获得的内存mmap()不计入数据段。

  • 这个假设是真的吗?这是否仅适用于 的非 POSIX 变体mmap()

4

1 回答 1

2

FreeBSD 也分享了 malloc(3) 在默认 malloc 实现中使用 mmap(2) 实现的问题。我在将产品从 FreeBSD 6 移植到 7 时遇到了这个问题,发生了切换。我们将每个进程的默认限制从 RLIMIT_DATA=512M 切换为 RLIMIT_VMEM=512M,即将虚拟内存分配限制为 512MB。

至于这是否违反POSIX,我不知道。我的直觉是,很多事情都违反了 POSIX,而 100% 符合 POSIX 的系统与严格确认的 C 编译器一样罕见。

编辑:呵呵,现在我看到 FreeBSD 的名称 RLIMIT_VMEM 是非标准的;他们将 RLIMIT_AS 定义为 RLIMIT_VMEM 以实现 POSIX 兼容性。

于 2014-05-20T21:48:05.280 回答