Linux應(yīng)用程序設(shè)計(jì):如何獲取線程棧的使用信息?
把以上代碼放在一起:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/resource.h>
void print_stack1()
{
size_t used, avail;
pthread_attr_t attr;
void *stack_addr;
int stack_size;
// 獲取棧寄存器 ESP 的當(dāng)前值
size_t esp_val;
asm("movl %%esp, %0" : "=m"(esp_val) :);
// 通過(guò)線程屬性,獲取棧區(qū)的起始地址和空間總大小
memset(&attr, 0, sizeof(pthread_attr_t));
pthread_getattr_np(pthread_self(), &attr);
pthread_attr_getstack(&attr, &stack_addr, &stack_size);
pthread_attr_destroy(&attr);
printf("espVal = %p ", esp_val);
printf("statck top = %p ", stack_addr);
printf("stack bottom = %p ", stack_addr + stack_size);
avail = esp_val - (size_t)stack_addr;
used = stack_size - avail;
printf("print_stack1: used = %d, avail = %d, total = %d ",
used, avail, stack_size);
}
int main(int argc, char *agv[])
{
print_stack1();
return 0;
}
雜牌軍方式
上面的正規(guī)軍方法,主要是通過(guò)系統(tǒng)函數(shù)獲取了線程的屬性信息,從而獲取了棧區(qū)的開(kāi)始地址和棧的總空間大小。
為了獲取這兩個(gè)值,調(diào)用了 3 個(gè)函數(shù),有點(diǎn)笨重!
不知各位小伙伴是否想起:Linux 操作系統(tǒng)會(huì)為一個(gè)應(yīng)用程序,都提供了一些關(guān)于 limit 的信息,這其中就包括堆棧的相關(guān)信息。
這樣的話,我們就能拿到一個(gè)線程的?臻g總大小了。
此時(shí),還剩下最后一個(gè)變量不知道:棧區(qū)的開(kāi)始地址!
我們來(lái)分析一下哈:當(dāng)一個(gè)線程剛剛開(kāi)始執(zhí)行的時(shí)候,棧區(qū)里可以認(rèn)為是空的,也就是說(shuō)此時(shí) ESP 寄存器里的值就可以認(rèn)為是指向棧區(qū)的開(kāi)始地址!
是不是有豁然開(kāi)朗的感覺(jué)?!
但是,這仍然需要調(diào)用匯編代碼來(lái)獲取。
再想一步,既然此時(shí)棧區(qū)里可以認(rèn)為是空的,那么如果在線程的第一個(gè)函數(shù)中,定義一個(gè)局部變量,然后通過(guò)獲取這個(gè)局部變量的地址,不就相當(dāng)于是獲取到了棧區(qū)的開(kāi)始地址了嗎?
如下圖所示:
我們可以把這個(gè)局部變量的地址,記錄在一個(gè)全局變量中。然后在應(yīng)用程序的其他代碼處,就可以用它來(lái)代表?xiàng)5钠鹗嫉刂贰?/p>
知道了 3 個(gè)必需的變量,就可以計(jì)算?臻g的使用情況了:
// 用來(lái)存儲(chǔ)棧區(qū)的起始地址
size_t top_stack;
void print_stack2()
{
size_t used, avail;
size_t esp_val;
asm("movl %%esp, %0" : "=m"(esp_val) :);
printf("esp_val = %p ", esp_val);
used = top_stack - esp_val;
struct rlimit limit;
getrlimit(RLIMIT_STACK, &limit);
avail = limit.rlim_cur - used;
printf("print_stack2: used = %d, avail = %d, total = %d ",
used, avail, used + avail);
}
int main(int argc, char *agv[])
{
int x = 0;
// 記錄棧區(qū)的起始地址(近似值)
top_stack = (size_t)&x;
print_stack2();
return 0;
}
更討巧的方式
在上面的兩種方法中,獲取棧的當(dāng)前指針位置的方式,都是通過(guò)匯編代碼,來(lái)獲取寄存器 ESP 中的值。
是否可以繼續(xù)利用剛才的技巧:通過(guò)定義一個(gè)局部變量的方式,來(lái)間接地獲取 ESP 寄存器的值?
void print_stack3()
{
int x = 0;
size_t used, avail;
// 局部變量的地址,可以近似認(rèn)為是 ESP 寄存器的值
size_t tmp = (size_t)&x;
used = top_stack - tmp;
struct rlimit limit;
getrlimit(RLIMIT_STACK, &limit);
avail = limit.rlim_cur - used;
printf("print_stack3: used = %d, avail = %d, total = %d ",
used, avail, used + avail);
}
int main(int argc, char *agv[])
{
int x = 0;
top_stack = (size_t)&x;
print_stack3();
return 0;
}
總結(jié)
以上的幾種方式,各有優(yōu)缺點(diǎn)。
我們把以上 3 個(gè)打印堆棧使用情況的函數(shù)放在一起,然后在 main 函數(shù)中,按順序調(diào)用 3 個(gè)測(cè)試函數(shù),每個(gè)函數(shù)中都定義一個(gè)整型數(shù)組(消耗 4K 的?臻g),然后看一下這幾種方式的打印輸出信息:
// 測(cè)試代碼(3個(gè)打印函數(shù)就不貼出來(lái)了)
void print_stack1()
{
...
}
void print_stack2()
{
...
}
void print_stack3()
{
...
}
void func3()
{
int num[1024];
print_stack1();
printf(" ********* ");
print_stack2();
printf(" ********* ");
print_stack3();
}
void func2()
{
int num[1024];
func3();
}
void func1()
{
int num[1024];
func2();
}
int main(int argc, char *agv[])
{
int x = 0;
top_stack = (size_t)&x;
func1();
return 0;
}
打印輸出信息:
espVal = 0xffe8c980
statck top = 0xff693000
stack bottom = 0xffe90000
print_stack1: used = 13952, avail = 8362368, total = 8376320
*********
esp_val = 0xffe8c9a0
print_stack2: used = 12456, avail = 8376152, total = 8388608
*********
print_stack3: used = 12452, avail = 8376156, total = 8388608

發(fā)表評(píng)論
請(qǐng)輸入評(píng)論內(nèi)容...
請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字
圖片新聞
-
機(jī)器人奧運(yùn)會(huì)戰(zhàn)報(bào):宇樹(shù)機(jī)器人摘下首金,天工Ultra搶走首位“百米飛人”
-
存儲(chǔ)圈掐架!江波龍起訴佰維,索賠121萬(wàn)
-
長(zhǎng)安汽車(chē)母公司突然更名:從“中國(guó)長(zhǎng)安”到“辰致科技”
-
豆包前負(fù)責(zé)人喬木出軌BP后續(xù):均被辭退
-
字節(jié)AI Lab負(fù)責(zé)人李航卸任后返聘,Seed進(jìn)入調(diào)整期
-
員工持股爆雷?廣汽埃安緊急回應(yīng)
-
中國(guó)“智造”背后的「關(guān)鍵力量」
-
小米汽車(chē)研發(fā)中心重磅落地,寶馬家門(mén)口“搶人”
最新活動(dòng)更多
-
10月23日火熱報(bào)名中>> 2025是德科技創(chuàng)新技術(shù)峰會(huì)
-
10月23日立即報(bào)名>> Works With 開(kāi)發(fā)者大會(huì)深圳站
-
10月24日立即參評(píng)>> 【評(píng)選】維科杯·OFweek 2025(第十屆)物聯(lián)網(wǎng)行業(yè)年度評(píng)選
-
11月27日立即報(bào)名>> 【工程師系列】汽車(chē)電子技術(shù)在線大會(huì)
-
12月18日立即報(bào)名>> 【線下會(huì)議】OFweek 2025(第十屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會(huì)
-
精彩回顧立即查看>> 【限時(shí)福利】TE 2025國(guó)際物聯(lián)網(wǎng)展·深圳站
推薦專(zhuān)題
- 1 先進(jìn)算力新選擇 | 2025華為算力場(chǎng)景發(fā)布會(huì)暨北京xPN伙伴大會(huì)成功舉辦
- 2 人形機(jī)器人,正狂奔在批量交付的曠野
- 3 宇樹(shù)機(jī)器人撞人事件的深度剖析:六維力傳感器如何成為人機(jī)安全的關(guān)鍵屏障
- 4 解碼特斯拉新AI芯片戰(zhàn)略 :從Dojo到AI5和AI6推理引擎
- 5 AI版“四萬(wàn)億刺激”計(jì)劃來(lái)了
- 6 2025年8月人工智能投融資觀察
- 7 8 a16z最新AI百?gòu)?qiáng)榜:硅谷頂級(jí)VC帶你讀懂全球生成式AI賽道最新趨勢(shì)
- 9 Manus跑路,大廠掉線,只能靠DeepSeek了
- 10 地平線的野心:1000萬(wàn)套HSD上車(chē)