精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

明明還有大量內存,為啥報錯“無法分配內存”?

系統 Linux
在Linux里創建進程時,如果在 pid 不足的時候竟然返回的錯誤提示是“內存不足”。這個不恰當的錯誤提示導致很多同學都困惑不已。

大家好,我是飛哥!

讀者群里一位同學的線上服務器出現一個詭異的問題,執行任何命令都是報錯“fork:無法分配內存”。這個問題最近出現的,前幾次重啟后解決的,但是每隔 2-3 天就會出現一次。

# service docker stop
-bash fork: 無法分配內存
# vi 1.txt
-bash fork: 無法分配內存

看到這個提示,大家的第一反應肯定是懷疑內存真的不夠了。我們這位讀者也是這么認為的。但查看內存占用卻發現根本沒有,內存還空閑了一大把!(多試幾次才有機會執行成功一次)

飛哥和群里的同學們一起參謀這個問題以后,幫出了三個思路。讓這位讀者回去挨個試。

1.是不是numa架構下,進程啟動的時候綁定了node,導致只有一個node里的內存在起作用?

2.numa架構下,如果所有內存都插到一個槽,其它node就會沒內存

3.查看下現在的進(線)程數是多少,是不是超過最大限制了

在經過一段時間的排查以后,這位讀者的問題順利解決。這里直接和大家匯報結論,前面關于 numa 內存不足的猜測是錯誤的。真實的原因是上面第 3 個,這臺服務器上面的某幾個java進程創建了太多的線程,導致了這個報錯的產生,并不真的是內存不夠。

一、底層過程分析

這個問題中,Linux 報錯提示存在誤導人的地方。導致大家并沒有第一時間往進程數上想。所以才有了這么復雜曲折的排錯過程,以至于在群里討論才得以解決。

于是我想深入到內核里看看,報錯到底是如何提示出來這么一個不恰當的錯誤提示的。然后順便咱們也來了解了解創建進程的過程。

讀者的線上服務器的操作系統是 CentOS 7.8,我查了一下對應的內核版本是 3.10.0-1127。

1.1 do_fork 剖析

在 Linux 內核里,無論是創建進程還是線程,都會調用到最核心的 do_fork 上來。在這個函數內部,通過拷貝的方式來創建新的進程(線程)所需要的內核數據對象。

//file:kernel/fork.c
long do_fork(unsigned long clone_flags, ...)
{
//所謂的創建,其實是根據當前進程進行拷貝
//注意:倒數第二個參數傳入的是 NULL
p = copy_process(clone_flags, stack_start, stack_size,
child_tidptr, NULL, trace);
...
}

整個進程創建的核心都是位于 copy_process 中,我們來看它的源碼。

//file:kernel/fork.c
static struct task_struct *copy_process(unsigned long clone_flags,
...
struct pid *pid,
int trace)
{
//內核表示進程(線程)的數據結構叫task_struct
struct task_struct *p;

......

//拷貝方式生成新進程的核心數據結構
p = dup_task_struct(current);

//拷貝方式生成新進程的其它核心數據
retval = copy_semundo(clone_flags, p);
retval = copy_files(clone_flags, p);
retval = copy_fs(clone_flags, p);
retval = copy_sighand(clone_flags, p);
retval = copy_mm(clone_flags, p);
retval = copy_namespaces(clone_flags, p);
retval = copy_io(clone_flags, p);
retval = copy_thread(clone_flags, stack_start, stack_size, p);

//注意這里!!!!!!
//申請整數形式的 pid 值
if (pid != &init_struct_pid) {
retval = -ENOMEM;
pid = alloc_pid(p->nsproxy->pid_ns);
if (!pid)
goto bad_fork_cleanup_io;
}

//將生成的整數pid值設置到新進程的 task_struct 上
p->pid = pid_nr(pid);
p->tgid = p->pid;
if (clone_flags & CLONE_THREAD)
p->tgid = current->tgid;

bad_fork_cleanup_io:
if (p->io_context)
exit_io_context(p);
......
fork_out:
return ERR_PTR(retval);
}

通過以上代碼可以看出,Linux 內核創建整個進程內核對象的創建過程都是通過分別調用不同的 copy_xxx 的方式來實現的,包括 mm 結構體、包括 namespaces等等。

我們來重點 alloc_pid 相關的這一段。在這一段中,目的是要申請一個 pid 對象出來。如果申請失敗就返回錯誤了。大家注意這段代碼的細節:無論 alloc_pid 返回的是何種類型的失敗,其錯誤類型都寫死的返回 -ENOMEM...... 為了方便大家理解,我單獨把這段邏輯再展示一遍。

//file:kernel/fork.c
static struct task_struct *copy_process(...){
......

//申請整數形式的 pid 值
if (pid != &init_struct_pid) {
retval = -ENOMEM;
pid = alloc_pid(p->nsproxy->pid_ns);
if (!pid)
goto bad_fork_cleanup_io;
}
bad_fork_cleanup_io:
...
fork_out:
return ERR_PTR(retval);
}

在準備調用 alloc_pid 的時候,直接就先將錯誤類型設置成了 -ENOMEM(retval = -ENOMEM),只要 alloc_pid 返回的不正確,都是將 ENOMEM 這個錯誤返回給上層。而不管 alloc_pid 內存究竟是因為什么原因產生的錯誤。

我們來查看一下 ENOMEM 的定義。它代表的是 Out of memory 的意思。(內核只是返回錯誤碼,應用層再給出具體的錯誤提示,所以實際提示的是中文的“無法分配內存”)。

//file:include/uapi/asm-generic/errno-base.h
#define ENOMEM 12 /* Out of memory */

不得不說。內核的這個錯誤提示太成問題了。給使用者造成了很大的困惑。

1.2 導致 alloc_pid 失敗的原因

那我們接著再來詳細看看都有哪些情況下分配 pid 會失敗呢?來看 alloc_pid 的源碼:

//file:kernel/pid.c
struct pid *alloc_pid(struct pid_namespace *ns)
{
//第一種情況:申請 pid 內核對象失敗
pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL);
if (!pid)
goto out;

//第二種情況:申請整數 pid 號失敗
//調用到alloc_pidmap來分配一個空閑的pid
tmp = ns;
pid->level = ns->level;
for (i = ns->level; i >= 0; i--) {
nr = alloc_pidmap(tmp);
if (nr < 0)
goto out_free;

pid->numbers[i].nr = nr;
pid->numbers[i].ns = tmp;
tmp = tmp->parent;
}

...
out:
return pid;
out_free:
goto out;
}

我們平時說的 pid 在內核中并不是一個簡單的整數類型,而是一個小結構體來表示的(struct pid),如下。

//file:include/linux/pid.h
struct pid
{
atomic_t count;
unsigned int level;
struct hlist_head tasks[PIDTYPE_MAX];
struct rcu_head rcu;
struct upid numbers[1];
};

所以需要先到內存中申請一塊內存用來存儲這個小對象。第一種錯誤情況是如果內存申請失敗,alloc_pid 會返回失敗。這種情況下確實是內存問題,出錯后內核返回 ENOMEM 無可厚非。

接著往下看第二種情況,alloc_pidmap 是要為當前的進程申請進程號,就是我們平時所說的 PID 編號。如果申請失敗,也會返回錯誤。

對于這種情況來說,只是分配進程編號出錯了,和內存不夠用半毛錢的關系都沒有。但在這種情況下內核卻會導致返回給上層的錯誤類型是 ENOMEM(Out of memory)。這實在是挺不合理的。

通過這里我們還額外學習到了另外一個知識!一個進程并不只是申請一個進程號就夠了。而是通過一個 for 循環去申請了多個。

//file:kernel/pid.c
struct pid *alloc_pid(struct pid_namespace *ns)
{
//調用到alloc_pidmap來分配一個空閑的pid
tmp = ns;
pid->level = ns->level;
for (i = ns->level; i >= 0; i--) {
nr = alloc_pidmap(tmp);
if (nr < 0)
goto out_free;

pid->numbers[i].nr = nr;
pid->numbers[i].ns = tmp;
tmp = tmp->parent;
}
}

假如說當前創建的進程是一個容器中的進程,那么它至少得申請兩個 PID 號才行。一個 PID 是在容器命名空間中的進程號,一個是根命名空間(宿主機)中的進程號。

這也符合我們平時的經驗。在容器中的每一個進程其實我們在宿主機中也都能看到。但是在容器中看到的進程號一般是和在宿主機上看到的是不一樣的。比如一個進程在容器中的 pid 是 5,在宿主機命名空間下是 1256。那么該進程在內核中的對象大概是如下這個樣子。

二、新版本是否有所改觀

接下來,我首先想到的可能是因為咱們用的內核版本太舊了。(熟悉飛哥的讀者都知道,我用的內核版本是 3.10.1,這是為了和我們公司線上服務器的版本保持一致。)

所以我又到非常新的 Linux 5.16.11 翻了一翻,看看新版本是否有修復這個不恰當的提示。

推薦一個工具:https://elixir.bootlin.com/ 。在這個網站上可以查看任意版本的 linux 內核源碼。如果只是臨時看一下,用它非常的合適。

//file:kernel/fork.c
static __latent_entropy struct task_struct *copy_process(...)
{
...
pid = alloc_pid(p->nsproxy->pid_ns_for_children, args->set_tid,
args->set_tid_size);
if (IS_ERR(pid)) {
retval = PTR_ERR(pid);
goto bad_fork_cleanup_thread;
}
}

貌似看起來有戲,retval 不再寫死的是 ENOMEM 了,而是根據 alloc_pid 實際的錯誤進行了設置。我們再來看 alloc_pid 是不是正確地設置錯誤類型了呢?

當我打開 alloc_pid 的源碼里,看到這一大段注釋的時候,我的心涼了半截......

//file:include/pid.c
struct pid *alloc_pid(struct pid_namespace *ns, ...)
{
/*
* ENOMEM is not the most obvious choice especially for the case
* where the child subreaper has already exited and the pid
* namespace denies the creation of any new processes. But ENOMEM
* is what we have exposed to userspace for a long time and it is
* documented behavior for pid namespaces. So we can't easily
* change it even if there were an error code better suited.
*/
retval = -ENOMEM;
.......

return retval
}

我把這段注釋給大家大致翻譯一下。它的意思是“ENOMEM不是最明顯的選擇,尤其是對于 pid 創建失敗的情況下。但是,ENOMEM 是我們長期暴露給用戶空間的東西。因此,即使有更適合的錯誤代碼,我們也無法輕易更改它”。

看到這兒,我想起了有不少人也稱 Linux 為屎山,可能這就是其中的一坨吧!最新的版本里也并沒有很好地解決這個問題。

結論

在 Linux 里創建進程時,如果在 pid 不足的時候竟然返回的錯誤提示是“內存不足”。這個不恰當的錯誤提示導致很多同學都困惑不已。

通過今天的文章,以后你再遇到這種內存不足錯誤的時候,你就要多留個心眼兒了,別被內核被蒙騙了,先來看看自己的進程(線程)數是不是過多了。

至于說發現了這個問題該如何解決嘛,可以通過修改內核參數加大可用 pid 數量(/proc/sys/kernel/pid_max)。

但是我覺得最根本的方法還是要揪出來為啥系統中會出現這么多的進程(線程),然后把它干掉。默認情況下的兩三萬個進程數對于絕大多數的服務器來說已經是一個過于龐大的數字了,連這個數都超過了,一定是不合理的。

責任編輯:武曉燕 來源: 開發內功修
相關推薦

2021-07-14 10:00:32

Python內存測量

2013-10-12 13:01:51

Linux運維內存管理

2022-09-05 08:39:55

Redis存儲數據

2010-09-25 14:12:50

Java內存分配

2021-02-28 13:22:54

Java內存代碼

2025-07-01 02:25:00

2023-10-18 13:31:00

Linux內存

2022-03-16 08:39:19

StackHeap內存

2013-10-12 11:15:09

Linux運維內存管理

2009-06-03 15:52:34

堆內存棧內存Java內存分配

2025-08-05 09:24:30

2025-06-09 04:00:00

2022-01-13 10:30:21

C語言內存動態

2011-07-15 01:10:13

C++內存分配

2021-12-16 06:52:33

C語言內存分配

2018-02-08 14:57:22

對象內存分配

2010-09-17 16:14:22

Java內存分配

2021-04-23 07:27:31

內存分配CPU

2010-09-25 15:40:52

配置JVM內存

2022-09-15 18:21:03

JVMKafka
點贊
收藏

51CTO技術棧公眾號

高清久久精品| 欧美黄色aaa| 欧美粗大gay| 欧美国产国产综合| 99porn视频在线| 国产美女激情视频| 免费成人av| 欧美一区二区三区在线观看 | 一区二区三区视频免费观看| 欧美午夜在线一二页| 国产女教师bbwbbwbbw| 天天干天天操av| 精品一区二区三区免费毛片爱| 欧美激情国产精品| 亚洲AV无码成人精品区明星换面| 精品亚洲a∨一区二区三区18| 黄色成人在线免费| 在线免费观看一区二区三区| 国模无码一区二区三区| 日韩成人免费看| 欧美成人一区在线| 精品一区二区三区蜜桃在线| 亚洲日本va| 欧美日韩中文字幕一区二区| www.av毛片| h视频在线免费观看| 久久婷婷色综合| 97在线电影| 在线视频1卡二卡三卡| 亚洲美女少妇无套啪啪呻吟| 日韩亚洲精品视频| 国产美女精品久久| 欧美大胆a级| 91精品国产aⅴ一区二区| 成人一区二区三| 啊啊啊久久久| 亚洲风情在线资源站| 亚洲欧美一二三| av在线日韩国产精品| 337p粉嫩大胆噜噜噜噜噜91av| 91黄色国产视频| 一级成人免费视频| 日本欧美韩国一区三区| 日本精品免费一区二区三区| 久久精品国产亚洲av香蕉 | 亚洲午夜国产成人av电影男同| 99re这里只有| 亚洲一级大片| 日韩欧美一级二级| 欧美国产日韩另类 | 国产91露脸合集magnet| 国产欧美韩国高清| 中文字幕无码乱码人妻日韩精品| 老鸭窝毛片一区二区三区| 97久久精品人搡人人玩| 激情视频在线播放| 很黄很黄激情成人| 色综合久综合久久综合久鬼88 | 污视频软件在线观看| 国产成人av电影在线观看| 亚洲精品免费网站| 精品国产999久久久免费| 久久精品72免费观看| 国产欧美精品va在线观看| 中文字幕乱码人妻二区三区| 青青草一区二区三区| 国产精品自在线| 国产精品欧美久久久久天天影视| 久88久久88久久久| 91久久久久久久一区二区| 国产精品日韩无码| 国产91对白在线观看九色| 超碰97在线资源| 日本韩国在线观看| 91老师片黄在线观看| 日本亚洲自拍| 91社区在线观看播放| 国产精品青草久久| 欧美一级特黄aaaaaa在线看片| 亚洲无线看天堂av| 99国产精品久久久久| 精品蜜桃传媒| 成年人在线视频| 日韩毛片一二三区| 久久人人爽人人爽人人av| 第一福利在线视频| 在线观看成人小视频| 亚洲欧美偷拍另类| 中文久久电影小说| 亚洲精品丝袜日韩| 97在线观看视频免费| 欧美日韩国产探花| 欧美中文在线字幕| 91美女精品网站| www.日韩在线| 午夜欧美性电影| 日本在线观看大片免费视频| 岛国av午夜精品| 国产又大又黄又粗又爽| 亚洲国产欧美国产第一区| 日韩精品在线免费观看| 天美传媒免费在线观看| 激情久久综合| 国产噜噜噜噜噜久久久久久久久| 亚洲黄色精品视频| 国产婷婷色一区二区三区四区| 男人天堂成人网| 欧美国产大片| 欧美电影免费观看完整版| 成都免费高清电影| 欧美激情视频一区二区三区在线播放| 17婷婷久久www| aaa国产视频| 国产午夜精品久久久久久免费视| 青青在线免费视频| 欧美7777| 亚洲成人中文字幕| 99成人在线观看| 久久av一区| 国产精品久久久久久久久久久久午夜片| 激情小视频在线| 亚洲一区二区三区在线播放| 9l视频白拍9色9l视频| 久久91在线| 久久久精品美女| а中文在线天堂| av毛片久久久久**hd| 综合网五月天| 日韩国产网站| 精品视频在线播放| 日韩免费视频网站| 国产福利一区在线| 97超碰免费观看| 成人激情视屏| 亚洲图片在线综合| 国产精品自拍99| 成人av在线资源网| 一本大道东京热无码aⅴ| 欧美日韩卡一| 中文精品99久久国产香蕉| 男人日女人网站| 99在线精品一区二区三区| 99中文字幕在线观看| 国产精品一区二区三区av | 国产精品探花一区二区在线观看| 欧美.www| 亚洲r级在线观看| www视频在线免费观看| 欧美久久久久免费| 亚洲一级二级片| 麻豆精品视频在线| 一区二区不卡在线观看| 国产精品久久久久久久久免费高清 | 国产精品第六页| 久久久国产精品午夜一区ai换脸| 国产精品沙发午睡系列| 欧美变态网站| 日韩av理论片| 国产小视频在线观看| 日本电影亚洲天堂一区| 蜜臀久久99精品久久久久久| 日精品一区二区| 神马影院一区二区| 另类一区二区| www国产91| 99久久国产免费| 亚洲精品一二三四区| 日本中文字幕有码| 欧美aa国产视频| 国产精品久久久久久久小唯西川 | 久久久爽爽爽美女图片| 亚洲黄色在线播放| 黄色一区二区在线| 精品少妇人妻一区二区黑料社区| 日韩黄色免费网站| 伊人av成人| 6080成人| 琪琪第一精品导航| 成年人在线免费观看| 91精品国产乱码久久蜜臀| 国产第100页| 久久久www免费人成精品| 国产精品久久久毛片| 久久久久国产| 精品在线不卡| 成人18视频在线观看| 欧美成人在线网站| 天堂网在线中文| 色久优优欧美色久优优| 国产喷水在线观看| 国产精品一区二区三区99| 波多野结衣家庭教师在线播放| 成人动漫免费在线观看| 91久久在线观看| 亚洲精品日产| 久久好看免费视频| 香港一级纯黄大片| 欧美久久免费观看| 黄色在线视频网址| 亚洲男人天堂av网| japanese中文字幕| 国产丶欧美丶日本不卡视频| 国产精品免费观看久久| 在线看片不卡| 丝袜足脚交91精品| 精品素人av| 91精品久久久久久久久中文字幕| yellow字幕网在线| 在线观看欧美www| 欧美亚洲精品在线观看| 欧美婷婷六月丁香综合色| 国产无码精品久久久| 中文字幕成人av| 日韩av无码一区二区三区不卡 | 成人6969www免费视频| 翡翠波斯猫1977年美国| 成人黄页网站视频| 日本久久久久久久久| 久久www人成免费看片中文| 在线成人激情黄色| 亚洲日本中文字幕在线| 日韩一区二区三区高清免费看看| 国产在线观看第一页| 激情亚洲一区二区三区四区| 91精品国产高清一区二区三蜜臀| 国产清纯美女被跳蛋高潮一区二区久久w| 老女人性生活视频| 麻豆精品视频在线观看免费| 日韩视频免费在线播放| 99国产精品私拍| 视色,视色影院,视色影库,视色网| 欧美色网址大全| 久久综合中文色婷婷| 国产91精品入| 高清国产在线一区| 日韩激情综合| 97人人模人人爽人人喊38tv| av在线成人| 成人妇女免费播放久久久| 成人在线不卡| 国产极品精品在线观看| 亚洲精品福利电影| 欧美夜福利tv在线| 国产伦理精品| 97色在线观看免费视频| sm久久捆绑调教精品一区| 欧美精品18videosex性欧美| 午夜小视频在线观看| 欧美大胆a视频| av毛片在线免费看| 美女av一区二区三区| a黄色片在线观看| 久久av在线看| 牛牛在线精品视频| 欧美精品第一页在线播放| 黄污视频在线观看| 久久久欧美一区二区| 乱人伦视频在线| 欧美在线播放视频| 日韩a**中文字幕| 国产精品欧美日韩| 一区在线不卡| 99视频网站| 任我爽精品视频在线播放| 美国av一区二区三区| 国产乱码精品一区二区三区四区| 日本在线视频不卡| 欧美国产一级| 5566中文字幕一区二区| 欧美激情三级| 国产精品久久精品国产| 天堂在线精品| 视频一区视频二区视频三区视频四区国产 | 色综合网站在线| 日韩黄色一级视频| 欧美日韩一区二区不卡| 99久久精品国产一区二区成人| 日韩午夜电影在线观看| 欧美一级淫片aaaaaa| 精品视频在线观看日韩| 成av人电影在线观看| 久久综合国产精品台湾中文娱乐网| 伊人手机在线| 欧美一区二区影院| japansex久久高清精品| 国产精品久久久对白| 狠狠综合久久av一区二区蜜桃| 国产福利片一区二区| 99在线观看免费视频精品观看| 日韩欧美黄色大片| 国产精品一品视频| 免费中文字幕av| 中文字幕一区免费在线观看| 国产一级片视频| 欧洲视频一区二区| a级片在线视频| 亚洲欧美中文字幕在线一区| 韩国中文字幕在线| 91豆花精品一区| 精品中文字幕一区二区三区| 久久本道综合色狠狠五月| 99精品电影| 日韩欧美视频网站| 黑人巨大精品欧美一区| 日本丰满少妇裸体自慰| 亚洲欧美另类小说视频| 国产成人精品777777| 日韩欧美的一区二区| 成人h小游戏| 欧美一级bbbbb性bbbb喷潮片| 国产精品一区二区三区av| 日本福利一区二区三区| 激情欧美亚洲| 99久久99精品| 麻豆91在线播放免费| 国产精品亚洲一区二区无码| 中文字幕av免费专区久久| 日本熟女一区二区| 欧美一区二区在线视频| 可以免费看污视频的网站在线| 欧美成人午夜免费视在线看片 | 91精彩视频在线观看| 97久久精品在线| 视频在线观看免费影院欧美meiju| 日本一区二区免费看| 亚洲影音一区| 少妇精品无码一区二区| 综合在线观看色| 国产99免费视频| 亚洲精品丝袜日韩| 国产精品一二三产区| 亚洲最大的av网站| 久久免费大视频| 色综合手机在线| 久久久久久黄色| av资源免费观看| 亚洲成人三级在线| 欧美1—12sexvideos| 91亚洲永久免费精品| 97在线精品| 亚洲一区日韩精品| 国产精品网曝门| 国产精品51麻豆cm传媒| 亚洲人成啪啪网站| 黄色综合网址| 久久综合一区| 久久久久久久欧美精品| free性中国hd国语露脸| 黄网动漫久久久| 性感美女一级片| 欧美在线一级va免费观看| 秋霞综合在线视频| aa在线免费观看| www成人在线观看| 五月天婷婷导航| 国产亚洲欧洲高清| 日本免费一区二区三区等视频| 亚洲一二三区精品| 蜜桃91丨九色丨蝌蚪91桃色| 女人裸体性做爰全过| 777久久久精品| 超碰在线免费公开| 超碰97在线人人| 99成人在线| 亚洲AV无码国产成人久久| 在线一区二区三区四区| 欧美激情午夜| 国模叶桐国产精品一区| www.亚洲一二| 狠狠97人人婷婷五月| 国产亚洲成年网址在线观看| 五月激情丁香网| 久久天天躁狠狠躁夜夜av| 亚洲**毛片| 久久婷婷五月综合色国产香蕉| 久久奇米777| 亚洲永久精品视频| 九九视频直播综合网| 欧美亚洲国产日韩| 日本特黄a级片| 亚洲午夜视频在线观看| 五月婷婷久久久| 国产精品旅馆在线| 韩国一区二区三区在线观看| 在线免费观看日韩av| 欧美乱妇15p| 看黄在线观看| 亚洲精品高清视频| 国产超碰在线一区| 日韩在线视频不卡| 美女啪啪无遮挡免费久久网站| 久久丝袜视频| 欧美男女交配视频| 亚洲成a人片在线不卡一二三区| 男人久久精品| 91黄色国产视频| 日韩电影免费在线| 久久在线视频精品| 中文日韩在线视频| 精品少妇一区|