pthread_create在可用内存不足的情况下使用ENOMEM失败

pthread_create在可用内存不足的情况下使用ENOMEM失败,c,linux,pthreads,C,Linux,Pthreads,我有一个SH4板,这是规格 uname -a Linux LINUX7109 2.6.23.17_stm23_A18B-HMP_7109-STSDK #1 PREEMPT Fri Aug 6 16:08:19 ART 2010 sh4 unknown 假设我已经吃掉了几乎所有的内存,只剩下9MB了 free total used free shared buffers cached Mem: 48072 42276

我有一个SH4板,这是规格

uname -a
Linux LINUX7109 2.6.23.17_stm23_A18B-HMP_7109-STSDK #1 PREEMPT Fri Aug 6 16:08:19 ART 2010
sh4 unknown
假设我已经吃掉了几乎所有的内存,只剩下9MB了

free
 total       used       free     shared    buffers     cached
Mem:         48072      42276       5796          0        172       3264
-/+ buffers/cache:      38840       9232
Swap:            0          0          0
现在,当我尝试使用默认堆栈大小(8MB)启动单个线程时 pthread_create使用ENOMEM失败。如果我仔细查看我的测试代码,我可以看到失败的函数是mmap:

old_mmap(NULL, 8388608, PROT_READ|PROT_WRITE|PROT_EXEC,                       
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
但是,当我使用ulimit-s将堆栈大小设置为较低的值时:

ulimit -s 7500
我现在可以启动10个线程。每个线程不分配任何内容,因此 只消耗最小的开销(每个线程大约8 kb,对吗?)

所以,我的问题是:

知道mmap实际上并不消耗内存, 当可用内存不足时,为什么pthread_create()(或mmap)会失败
线程堆栈大小?

在glibc下,线程的默认堆栈大小为2-10兆字节(通常为8兆字节)。您应该使用
pthread\u attr\u setstacksize
并对结果属性对象调用
pthread\u create
,以请求具有较小堆栈的线程。

mmap
消耗地址空间

指针必须唯一地标识内存中的一段“内存”(包括mmap文件)

32位指针只能寻址2/3GB内存(32bit=2^32=4GB。但内核保留了一些地址空间)。这个地址空间是有限的


进程中的所有线程共享相同的地址空间,但不同的进程有不同的地址空间。

虚拟机设置
/proc/sys/VM/overcommit_memory
(也称为sysctl VM.overcommit_memory)控制Linux是否愿意分配比机器的组合RAM+交换更多的地址空间。(当然,如果你真的试图访问那么多内存,某些东西会崩溃。尝试搜索“linux oom killer”…)


此设置的默认值为0。我想可能是有人在您的系统上设置了其他选项。

这是操作系统唯一一次操作失败的机会。如果实现允许此操作成功,则可能会在无法返回失败代码的操作(如堆栈增长)期间耗尽内存。操作系统宁愿让操作优雅地失败,也不愿冒着杀死一个完全无辜的进程的风险。

这不是我要问的,我知道我可以降低堆栈,但这并不能改变这样一个事实,即当空闲内存低于线程堆栈大小时,我无法创建另一个线程。您衡量“空闲内存”的方法这是错误的。查看
/proc/meminfo
中的行
CommitLimit
(总可用)和
Commit\u AS
(使用量)。我的测量方法可能错误。但是
CommitLimit
也不太正确。从
proc.txt
:“只有在启用了严格的超额分配记帐(vm.overmit_memory中的模式2)时,才会遵守此限制。”我的超额分配_内存为零。无论如何,谢谢你的提示,看来我必须深入内核mm才能找到答案;然而,情况并非如此。记住,我连一条线都发动不了。显然,它有足够的地址空间(8MB)。@Ezequiel Garcia-你确定吗?我不确定实现细节,但有可能相关代码优先选择某些正在使用的地址范围,并且永远不会考虑免费的范围。@ Ezequiel Garc Ia,尝试<代码> CAT/PROC//MAPs<代码>,检查内存映射。您能支持这个答案吗?我想知道至少我可以在内核源代码中查找到哪里。
vm/overmit
为零,但我认为这有点相关。是的,这个设置比我记忆中的要复杂得多。。。显然,“0”表示“有点过度”,“1”表示“过多”,而“2”表示“过少”。或者类似的。我认为细节可能已经从内核版本变为内核版本。。。