新聞中心
Linux內(nèi)核是現(xiàn)代操作系統(tǒng)中常用的一種,它的核心是內(nèi)核。Linux內(nèi)核本身是由C語言編寫的,它實(shí)現(xiàn)了操作系統(tǒng)中最基本的功能,例如進(jìn)程管理、內(nèi)存管理和文件系統(tǒng)等。對于Linux內(nèi)核而言,線程是一個(gè)非常重要的概念,線程堆棧作為線程的重要組成部分,其實(shí)現(xiàn)和優(yōu)化對Linux內(nèi)核的性能和穩(wěn)定性都有很大的影響。因此,本文就深入探究linux內(nèi)核線程堆棧的原理和優(yōu)化方法。

一、線程堆棧的概念和作用
線程是引入到操作系統(tǒng)中的一種新的程序執(zhí)行實(shí)體,它可以獨(dú)立執(zhí)行,與其他線程并發(fā)執(zhí)行。線程堆棧是線程的重要組成部分,它是線程運(yùn)行時(shí)保存本地變量、參數(shù)和返回地址信息的存儲區(qū)域。線程的每次函數(shù)調(diào)用都需要在堆棧上分配一定大小的空間,將函數(shù)的參數(shù)、函數(shù)局部變量和函數(shù)返回地址等信息存儲到堆棧中。當(dāng)函數(shù)返回時(shí),棧中存儲的數(shù)據(jù)將被彈出,棧指針也會恢復(fù)到原來的位置。因此,線程堆棧實(shí)際上記錄了線程的執(zhí)行過程。線程堆棧在Linux內(nèi)核中的作用包括:
1. 存儲線程的本地變量、參數(shù)和返回地址等信息。
2. 記錄線程執(zhí)行函數(shù)的調(diào)用關(guān)系,保證函數(shù)的正確返回。
3. 存儲異常處理信息,保證線程的異常處理能力。
二、Linux內(nèi)核線程堆棧的實(shí)現(xiàn)原理
Linux內(nèi)核線程堆棧的具體實(shí)現(xiàn)機(jī)制依賴于Linux內(nèi)核版本和CPU架構(gòu)。本文圍繞x86-64架構(gòu)和4.10.0版本的Linux內(nèi)核展開。在Linux內(nèi)核中,線程堆棧是通過頁表機(jī)制實(shí)現(xiàn)的。頁表是將線性地址映射到物理地址的數(shù)據(jù)結(jié)構(gòu),是內(nèi)核和硬件協(xié)同工作的重要元素,它負(fù)責(zé)將虛擬地址映射到物理地址,使得系統(tǒng)可以快速訪問內(nèi)存。Linux內(nèi)核線程堆棧的實(shí)現(xiàn)流程可以概括為以下3個(gè)步驟:
1. 分配棧內(nèi)存
當(dāng)線程被創(chuàng)建時(shí),內(nèi)核需要為該線程分配棧內(nèi)存。在x86-64中,內(nèi)核將??臻g劃分為多個(gè)頁,每個(gè)頁大小為4KB。內(nèi)核將連續(xù)的若干頁映射到一個(gè)虛擬地址空間上,這個(gè)虛擬地址稱為線程的棧頂?shù)刂罚╯tack pointer)。內(nèi)核通過調(diào)用kmalloc函數(shù)從內(nèi)核內(nèi)存池中分配相應(yīng)大小的內(nèi)存空間,以完成對棧內(nèi)存的分配。
2. 記錄棧指針
分配完棧內(nèi)存之后,內(nèi)核需要跟蹤線程的棧指針(stack pointer)。棧指針是指向棧頂?shù)闹羔?,用于?biāo)記當(dāng)前線程??臻g的使用情況。因?yàn)闂?臻g是一個(gè)先進(jìn)后出(FILO)的內(nèi)存結(jié)構(gòu),內(nèi)核需要始終保持該棧指針在??臻g內(nèi)部。因此,每次線程調(diào)用函數(shù)時(shí),內(nèi)核將該函數(shù)的參數(shù)、返回地址等信息存儲到堆棧中,并更新棧指針的位置,使其指向下一個(gè)可用位置。
3. 處理異常情況
線程堆棧不僅僅是一個(gè)邏輯上的概念,實(shí)際上它還承擔(dān)著異常處理的功能。當(dāng)線程執(zhí)行出錯(cuò)時(shí),則需要更新棧指針的位置,并將出錯(cuò)的現(xiàn)場信息存儲到棧上,以準(zhǔn)確記錄出錯(cuò)情況。如果出現(xiàn)棧溢出現(xiàn)象,則需要內(nèi)核的異常處理機(jī)制介入,以防止系統(tǒng)的嚴(yán)重崩潰和數(shù)據(jù)損壞。
三、線程堆棧的性能優(yōu)化方法
1. 使用大頁
在Linux內(nèi)核中,大頁是指4KB以上的物理頁面大小,它可以有效地減少頁表的數(shù)量。這樣在訪問內(nèi)存時(shí)可以更快地轉(zhuǎn)換虛擬地址到物理地址,從而提高系統(tǒng)的性能。因此,使用大頁可以優(yōu)化線程堆棧的頁表操作,實(shí)現(xiàn)更高效的內(nèi)存訪問。
2. 意識緩存層次結(jié)構(gòu)
現(xiàn)代CPU都有多級緩存,緩存能夠提高內(nèi)存訪問效率。在線程堆棧中,緩存層次結(jié)構(gòu)對于性能也有重要的影響。因此,對于對線程堆棧數(shù)據(jù)的訪問,需要注意緩存層次結(jié)構(gòu),利用緩存機(jī)制來提高訪問效率。例如,可以使用局部性原理,將經(jīng)常訪問的數(shù)據(jù)存儲在緩存中,減少底層內(nèi)存運(yùn)算;或在多線程應(yīng)用程序中,使用線程本地存儲技術(shù)來避免線程之間的競爭。
3. 避免過多的內(nèi)存分配
每次在線程堆棧中訪問函數(shù)參數(shù)時(shí),內(nèi)核都需要分配一段新的內(nèi)存空間。如果這個(gè)過程過于頻繁,在內(nèi)存管理上會產(chǎn)生一定的開銷。因此,為了避免過多的內(nèi)存分配,可以盡量減少函數(shù)參數(shù)的數(shù)量,將參數(shù)打包傳遞;或通過靜態(tài)分配存儲空間,避免重復(fù)分配。
四、
線程堆棧是Linux內(nèi)核中的重要概念,其實(shí)現(xiàn)機(jī)制和優(yōu)化方法對系統(tǒng)的性能和穩(wěn)定性有著至關(guān)重要的影響。本文就Linux內(nèi)核線程堆棧的原理和優(yōu)化方法進(jìn)行了深入探究。值得注意的是,不同版本的內(nèi)核對于線程堆棧的實(shí)現(xiàn)和優(yōu)化方法也有所不同,需要根據(jù)具體情況進(jìn)行調(diào)整。未來我們應(yīng)持續(xù)關(guān)注Linux內(nèi)核的發(fā)展,從中發(fā)掘更多革新性的設(shè)計(jì)和實(shí)踐。
相關(guān)問題拓展閱讀:
- 請教linux下用戶態(tài)進(jìn)程調(diào)度問題
請教linux下用戶態(tài)進(jìn)程調(diào)度問題
在進(jìn)行Linux系統(tǒng)操作的時(shí)候,有時(shí)候會遇到一次用戶態(tài)進(jìn)程死循環(huán),即系統(tǒng)反應(yīng)遲鈍、進(jìn)程掛死等問題,那么遇到這些問題又該如何解決呢?下面小編就給大家介紹下一次用戶態(tài)進(jìn)程死循環(huán)的問題該如何處瞎顫理。
Linux下如何處理一次用戶態(tài)進(jìn)程死循環(huán)問題
1、問題現(xiàn)象
業(yè)務(wù)進(jìn)程(用戶態(tài)多線程程序)掛死,操作系統(tǒng)反應(yīng)遲鈍,系統(tǒng)日志沒有任何異常。從進(jìn)程的內(nèi)核態(tài)堆棧看,看似所有線程都卡在了內(nèi)核態(tài)的如下堆棧流程中:
?。踨oot@vmc116 ~]# cat /proc/27007/task/11825/stack
?。邸秄fffffff8100baf6》] retint_careful+0x14/0x32
?。邸秄fffffffffffffff》] 0xffffffffffffffff
2、喊兄問題分析
1)內(nèi)核堆棧分析
從內(nèi)核堆??矗羞M(jìn)程都阻塞在 retint_careful上,這個(gè)是中斷返回過程中的流程,代碼(匯編)如下:
entry_64.S
代碼如下:
ret_from_intr:
DISABLE_INTERRUPTS(CLBR_NONE)
TRACE_IRQS_OFF
decl PER_CPU_VAR(irq_count)
/* Restore saved previous stack */
popq %rsi
CFI_DEF_CFA rsi,SS+8-RBP /* reg/off reset after def_cfa_expr */
leaq ARGOFFSET-RBP(%rsi), %rsp
CFI_DEF_CFA_REGISTER rsp
CFI_ADJUST_CFA_OFFSET RBP-ARGOFFSET
。。。
retint_careful:
CFI_RESTORE_STATE
bt $TIF_NEED_RESCHED,%edx
jnc retint_signal
TRACE_IRQS_ON
ENABLE_INTERRUPTS(CLBR_NONE)
pushq_cfi %rdi
磨滲敗 SCHEDULE_USER
popq_cfi %rdi
GET_THREAD_INFO(%rcx)
DISABLE_INTERRUPTS(CLBR_NONE)
TRACE_IRQS_OFF
jmp retint_check
這其實(shí)是用戶態(tài)進(jìn)程在用戶態(tài)被中斷打斷后,從中斷返回的流程,結(jié)合retint_careful+0x14/0x32,進(jìn)行反匯編,可以確認(rèn)阻塞的點(diǎn)其實(shí)就在
SCHEDULE_USER
這其實(shí)就是調(diào)用schedule()進(jìn)行調(diào)度,也就是說當(dāng)進(jìn)程走到中斷返回的流程中時(shí),發(fā)現(xiàn)需要調(diào)度(設(shè)置了TIF_NEED_RESCHED),于是在這里發(fā)生了調(diào)度。
有一個(gè)疑問:為什么在堆棧中看不到schedule()這一級的棧幀呢?
因?yàn)檫@里是匯編直接調(diào)用的,沒有進(jìn)行相關(guān)棧幀壓棧和上下文保存操作。
2)進(jìn)行狀態(tài)信息分析
從top命令結(jié)果看,相關(guān)線程實(shí)際一直處于R狀態(tài),CPU幾乎完全耗盡,而且絕大部分都消耗在用戶態(tài):
?。踨oot@vmc116 ~]# top
top – 09:42:23 up 16 days, 2:21, 23 users, load average: 84.08, 84.30, 83.62
Tasks: 1037 total, 85 running, 952 sleeping, 0 stopped, 0 zombie
Cpu(s): 97.6%us, 2.2%sy, 0.2%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem:k total,k used,k free,k buffers
Swap:k total, 38644k used,k free,k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
rootm 163m 14m R 10.2 0.5 321:06.17 z_itask_templat
rootm 163m 14m R 10.2 0.5 296:23.37 z_itask_templat
rootm 163m 14m R 10.2 0.5 337:57.26 z_itask_templat
rootm 163m 14m R 10.2 0.5 327:31.93 z_itask_templat
rootm 163m 14m R 10.2 0.5 306:49.44 z_itask_templat
rootm 163m 14m R 10.2 0.5 310:47.41 z_itask_templat
rootm 163m 14m R 10.2 0.5 283:03.37 z_itask_templat
rootm 163m 14m R 10.2 0.5 283:49.67 z_itask_templat
rootm 163m 14m R 10.2 0.5 261:24.46 z_itask_templat
rootm 163m 14m R 10.2 0.5 150:24.53 z_itask_templat
rootm 163m 14m R 10.2 0.5 100:26.77 z_itask_templat
rootm 163m 14m R 9.9 0.5 337:18.77 z_itask_templat
rootm 163m 14m R 9.9 0.5 314:24.17 z_itask_templat
rootm 163m 14m R 9.9 0.5 336:32.78 z_itask_templat
rootm 163m 14m R 9.9 0.5 338:55.08 z_itask_templat
rootm 163m 14m R 9.9 0.5 306:46.08 z_itask_templat
rootm 163m 14m R 9.9 0.5 316:49.51 z_itask_templat
。。。
3)進(jìn)程調(diào)度信息
從相關(guān)線程的調(diào)度信息看:
?。踨oot@vmc116 ~]# cat /proc/27007/task/11825/schedstat
?。踨oot@vmc116 ~]# cat /proc/27007/task/11825/schedstat
[root@vmc116 ~]# cat /proc/27007/task/11825/schedstat
?。踨oot@vmc116 ~]# cat /proc/27007/task/11825/schedstat
[root@vmc116 ~]# cat /proc/27007/task/11825/schedstat
發(fā)現(xiàn)相關(guān)線程的調(diào)度統(tǒng)計(jì)一直在增加,說明相關(guān)線程一直是在被調(diào)度運(yùn)行的,結(jié)合其狀態(tài)也一直是R,推測很可能在用戶態(tài)發(fā)生了死循環(huán)(或者非睡眠死鎖)。
這里又有問題:為什么從top看每個(gè)線程的CPU占用率只有10%左右,而不是通??吹降乃姥h(huán)進(jìn)程導(dǎo)致的100%的占用率?
因?yàn)榫€程數(shù)很多,而且優(yōu)先級都一樣,根據(jù)CFS調(diào)度算法,會平均分配時(shí)間片,不會讓其中一個(gè)線程獨(dú)占CPU。結(jié)果為多個(gè)線程間輪流調(diào)度,消耗掉了所有的cpu。。
另一個(gè)問題:為什么這種情況下,內(nèi)核沒有檢測到softlockup?
因?yàn)闃I(yè)務(wù)進(jìn)程的優(yōu)先級不高,不會影響watchdog內(nèi)核線程(更高優(yōu)先級的實(shí)時(shí)線程)的調(diào)度,所以不會產(chǎn)生softlockup的情況。
再一個(gè)問題:為什么每次查看線程堆棧時(shí),總是阻塞在retint_careful,而不是其它地方?
因?yàn)檫@里(中斷返回的時(shí)候)正是調(diào)度的時(shí)機(jī)點(diǎn),在其它時(shí)間點(diǎn)不能發(fā)生調(diào)度(不考慮其它情況~),而我們查看線程堆棧的行為,也必須依賴于進(jìn)程調(diào)度,所以我們每次查看堆棧時(shí),正是查看堆棧的進(jìn)程(cat命令)得到調(diào)度的時(shí)候,這時(shí)正是中斷返回的時(shí)候,所以正好看到的阻塞點(diǎn)為retint_careful。
4)用戶態(tài)分析
從上面的分析看,推測應(yīng)該是用戶態(tài)發(fā)生了死鎖。
用戶態(tài)確認(rèn)方法:
部署debug信息,然后gdb attach相關(guān)進(jìn)程,確認(rèn)堆棧,并結(jié)合代碼邏輯分析。
最終確認(rèn)該問題確為用戶態(tài)進(jìn)程中產(chǎn)生了死循環(huán)。
關(guān)于linux內(nèi)核線程堆棧的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
香港服務(wù)器選創(chuàng)新互聯(lián),2H2G首月10元開通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)互聯(lián)網(wǎng)服務(wù)提供商,擁有超過10年的服務(wù)器租用、服務(wù)器托管、云服務(wù)器、虛擬主機(jī)、網(wǎng)站系統(tǒng)開發(fā)經(jīng)驗(yàn)。專業(yè)提供云主機(jī)、虛擬主機(jī)、域名注冊、VPS主機(jī)、云服務(wù)器、香港云服務(wù)器、免備案服務(wù)器等。
新聞名稱:深入探究Linux內(nèi)核線程堆棧:原理分析與優(yōu)化方法(linux內(nèi)核線程堆棧)
轉(zhuǎn)載注明:http://m.fisionsoft.com.cn/article/copjdeh.html


咨詢
建站咨詢
