91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何實(shí)時(shí)獲取棧的使用情況?

Linux閱碼場(chǎng) ? 來源:IOT物聯(lián)網(wǎng)小鎮(zhèn) ? 作者:道哥 ? 2021-06-11 14:42 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

對(duì)于線程的??臻g,相信各位小伙伴都不陌生。它有下面的這幾項(xiàng)特性:

操作系統(tǒng)分配固定的空間;

使用一個(gè)棧寄存器來保存實(shí)時(shí)位置;

后進(jìn)先出。

poYBAGDDBxmAM_DoAABkwzITDso774.jpg

今天,我們不聊操作系統(tǒng)層面對(duì)棧的管理,只從應(yīng)用程序的角度,來看一下如何實(shí)時(shí)獲取棧的使用情況。

在一般的單片機(jī)/嵌入式程序開發(fā)過程中,在創(chuàng)建一個(gè)線程(或者稱作任務(wù))的時(shí)候,是可以指定給該線程分配多少棧空間的。

然后在調(diào)試的時(shí)候呢,周期性的打印出棧區(qū)的使用情況:消耗了多少空間,還剩余多少空間。

這樣的話,跑完每一個(gè)測(cè)試用例之后,就能得到一個(gè)大致的統(tǒng)計(jì)數(shù)據(jù),從而最終決定:需要給這個(gè)線程分配多少??臻g。

例如:在 ucOS 系統(tǒng)中,提供了函數(shù) NT8U OSTaskStkChk(INT8U prio, OS_STK_DATA *p_stk_data),來獲取一個(gè)任務(wù)的棧使用信息。

但是在 Linux 系統(tǒng)中,并沒有這樣類似的函數(shù),來直接獲取棧使用信息。

因此,為了得到此線程的已使用和空閑??臻g,必須通過其他的方式來獲取。

下面,就提供 2 種解決方案:正規(guī)軍方式和雜牌軍方式!

正規(guī)軍方式

在 Linux 系統(tǒng)中,在創(chuàng)建一個(gè)線程的時(shí)候,是可以通過線程屬性來設(shè)置:為這個(gè)線程分配多少的棧(stack)空間的。

如果應(yīng)用程序不指定的話,操作系統(tǒng)就設(shè)置為一個(gè)默認(rèn)的值。

線程創(chuàng)建完畢之后,操作系統(tǒng)在內(nèi)核空間,記錄了這個(gè)線程的一切信息,當(dāng)然也就包括給它分配的??臻g信息。

為了讓應(yīng)用層能夠獲取到這個(gè)信息,操作系統(tǒng)也提供了相應(yīng)的系統(tǒng)函數(shù)。代碼如下:

pthread_attr_t attr; void *stack_addr; int stack_size; 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("statck top = %p ", stack_addr); printf("stack bottom = %p ", stack_addr + stack_size);

從上面這段代碼中可以看到,它只能獲取棧空間的地址開始以及總的空間大小,仍然不知道當(dāng)前棧空間的實(shí)際使用情況!

我找了一下相關(guān)的系統(tǒng)調(diào)用,Linux 似乎沒有提供相關(guān)的函數(shù)。

怎么辦?只能迂回操作。

我們知道,在 Linux x86 平臺(tái)上,寄存器 ESP 就是來存儲(chǔ)棧指針的。對(duì)于一個(gè)滿遞減類型的棧,這個(gè)寄存器里的值,就代表了當(dāng)前棧中最后背使用的、那個(gè)棧空間的地址。

因此,只要我們能夠獲取到 ESP 寄存器里的值,就相當(dāng)于知道了當(dāng)前這個(gè)棧有多少空間被使用了。

那么怎樣來獲取 ESP 寄存器的值呢?既然是寄存器,那就肯定是使用匯編代碼了。

很簡(jiǎn)單,就 1 行:

size_t esp_val; asm("movl %%esp, %0" : "=m"(esp_val) :);

對(duì)不起,我錯(cuò)了!應(yīng)該是 2 行代碼,忘記變量定義了。

對(duì)于匯編代碼不熟悉的小伙伴,可以參考之前總結(jié)的一篇文章:內(nèi)聯(lián)匯編很可怕嗎?看完這篇文章,終結(jié)它!

找到第 4 個(gè)示例,直接抄過來就行。

好了,拿到了以上的所有信息,就可以計(jì)算出棧的已使用和空閑空間的大小了:

pYYBAGDDByWAHho6AACNOzmIkjw086.jpg

把以上代碼放在一起:

#include #include #include #include #include #include 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) :); // 通過線程屬性,獲取棧區(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ī)軍方法,主要是通過系統(tǒng)函數(shù)獲取了線程的屬性信息,從而獲取了棧區(qū)的開始地址和棧的總空間大小。

為了獲取這兩個(gè)值,調(diào)用了 3 個(gè)函數(shù),有點(diǎn)笨重!

不知各位小伙伴是否想起:Linux 操作系統(tǒng)會(huì)為一個(gè)應(yīng)用程序,都提供了一些關(guān)于 limit 的信息,這其中就包括堆棧的相關(guān)信息。

這樣的話,我們就能拿到一個(gè)線程的棧空間總大小了。

此時(shí),還剩下最后一個(gè)變量不知道:棧區(qū)的開始地址!

我們來分析一下哈:當(dāng)一個(gè)線程剛剛開始執(zhí)行的時(shí)候,棧區(qū)里可以認(rèn)為是空的,也就是說此時(shí) ESP 寄存器里的值就可以認(rèn)為是指向棧區(qū)的開始地址!

是不是有豁然開朗的感覺?!

但是,這仍然需要調(diào)用匯編代碼來獲取。

再想一步,既然此時(shí)棧區(qū)里可以認(rèn)為是空的,那么如果在線程的第一個(gè)函數(shù)中,定義一個(gè)局部變量,然后通過獲取這個(gè)局部變量的地址,不就相當(dāng)于是獲取到了棧區(qū)的開始地址了嗎?

如下圖所示:

poYBAGDDBy2AO4IjAAB0JZhoSaY067.jpg

我們可以把這個(gè)局部變量的地址,記錄在一個(gè)全局變量中。然后在應(yīng)用程序的其他代碼處,就可以用它來代表?xiàng)5钠鹗嫉刂贰?/p>

知道了 3 個(gè)必需的變量,就可以計(jì)算??臻g的使用情況了:

// 用來存儲(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)前指針位置的方式,都是通過匯編代碼,來獲取寄存器 ESP 中的值。

是否可以繼續(xù)利用剛才的技巧:通過定義一個(gè)局部變量的方式,來間接地獲取 ESP 寄存器的值?

poYBAGDDBzSAGqsWAACfTuCL0kY932.jpg

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 的棧空間),然后看一下這幾種方式的打印輸出信息:

// 測(cè)試代碼(3個(gè)打印函數(shù)就不貼出來了) 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

責(zé)任編輯:lq6

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    509

    瀏覽量

    20829
  • ??臻g
    +關(guān)注

    關(guān)注

    0

    文章

    5

    瀏覽量

    5547

原文標(biāo)題:Linux應(yīng)用程序設(shè)計(jì):用一種討巧方式,來獲取線程棧的使用信息

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    一次系統(tǒng)時(shí)間不同步問題的處理記錄(含 NTS-886003 的使用情況

    項(xiàng)目中多套系統(tǒng)、設(shè)備時(shí)間未統(tǒng)一,導(dǎo)致日志、視頻等時(shí)間不一致,排查困難。經(jīng)分析,采用專用授時(shí)設(shè)備NTS-886003作為內(nèi)部唯一時(shí)間源,實(shí)現(xiàn)全系統(tǒng)統(tǒng)一對(duì)時(shí),解決時(shí)間偏差問題。經(jīng)驗(yàn)表明,多設(shè)備系統(tǒng)應(yīng)盡早統(tǒng)一時(shí)間規(guī)劃,避免后期高成本改造
    的頭像 發(fā)表于 01-21 13:57 ?756次閱讀

    客戶使用profinet轉(zhuǎn)devicenet協(xié)議網(wǎng)關(guān)的使用情況分享

    Profinet
    jf_69310483
    發(fā)布于 :2025年12月03日 14:28:31

    Stack到底用來干嘛的呢?

    我們?cè)诤瘮?shù)的局部變量、數(shù)組這些不能超過1K(含嵌套的函數(shù)),否則程序就會(huì)崩潰進(jìn)入hardfaul。 除了這些局部變量以外,還有一些實(shí)時(shí)操作系統(tǒng)的現(xiàn)場(chǎng)保護(hù)、返回地址都是存儲(chǔ)在里面。 還有一點(diǎn)題外話,就是的增長(zhǎng)方向是從高地址到低
    發(fā)表于 12-01 08:04

    在Keil5中查看大小

    :打開生成的.map文件,在Image Symbol Table部分查找的相關(guān)信息,包括的大小和使用情況。 3、利用IDE的功能: 方法說明:Keil編譯器在編譯過程中會(huì)自動(dòng)跟蹤堆棧的使
    發(fā)表于 11-14 06:32

    如何檢查EZ-USB? CX3 上的 SRAM 使用情況(JTAG 不可用)?

    型的調(diào)試工具來實(shí)時(shí)監(jiān)控內(nèi)存使用情況。 是否有其他方法(例如構(gòu)建報(bào)告、SDK 功能或EZ-USB? Suite 內(nèi)的工具)可以讓我檢查固件使用了多少 SRAM?
    發(fā)表于 11-11 06:33

    如何在應(yīng)用程序調(diào)試期間分析和堆使用情況

    隨著 AMD Vitis 統(tǒng)一軟件平臺(tái) 2021.2 的發(fā)布,Vitis 引入了一個(gè) Tcl 腳本,用于在應(yīng)用程序運(yùn)行的特定時(shí)間點(diǎn)協(xié)助查找和堆的內(nèi)存使用情況。該腳本已延續(xù)到后續(xù)的 Vitis 版本
    的頭像 發(fā)表于 10-24 16:54 ?906次閱讀
    如何在應(yīng)用程序調(diào)試期間分析<b class='flag-5'>棧</b>和堆<b class='flag-5'>使用情況</b>

    手機(jī)無線充電發(fā)熱量

    無線充電發(fā)熱源于能量損耗,受材質(zhì)、環(huán)境溫度及使用情況影響,需注意散熱以保護(hù)手機(jī)。
    的頭像 發(fā)表于 10-13 08:14 ?1211次閱讀
    手機(jī)無線充電發(fā)熱量

    電腦監(jiān)控軟件有哪些方法?3款超簡(jiǎn)單的電腦監(jiān)控方法,實(shí)時(shí)監(jiān)控電腦

    在數(shù)字化快速發(fā)展的時(shí)代,電腦成為人們工作、學(xué)習(xí)和生活中不可或缺的工具。隨之而來,電腦監(jiān)控對(duì)于不同群體有著重要意義。企業(yè)管理者需要了解員工電腦使用情況,這就促使我們?nèi)ヌ剿饔行У碾娔X監(jiān)控方法,其中信企衛(wèi)
    的頭像 發(fā)表于 08-24 16:33 ?722次閱讀
    電腦監(jiān)控軟件有哪些方法?3款超簡(jiǎn)單的電腦監(jiān)控方法,<b class='flag-5'>實(shí)時(shí)</b>監(jiān)控電腦

    請(qǐng)問如何在Keil開發(fā)環(huán)境中查看代碼大小和SRAM使用情況

    如何在Keil開發(fā)環(huán)境中查看代碼大小和SRAM使用情況?
    發(fā)表于 08-20 06:38

    揭秘抖音視頻詳情API:電商行業(yè)的制勝法寶與實(shí)時(shí)數(shù)據(jù)獲取的奧秘

    隨著社交媒體的普及和電商行業(yè)的快速發(fā)展,抖音等短視頻平臺(tái)已經(jīng)成為電商企業(yè)獲取用戶、推廣產(chǎn)品和了解市場(chǎng)趨勢(shì)的重要渠道。獲取[抖音視頻詳情API]對(duì)于電商行業(yè)來說具有重要意義,它可以幫助企業(yè)實(shí)時(shí)
    的頭像 發(fā)表于 08-14 15:47 ?726次閱讀
    揭秘抖音視頻詳情API:電商行業(yè)的制勝法寶與<b class='flag-5'>實(shí)時(shí)</b>數(shù)據(jù)<b class='flag-5'>獲取</b>的奧秘

    請(qǐng)問如何僅使用軟件和 TC375 精簡(jiǎn)板來測(cè)量函數(shù)調(diào)用的堆棧使用情況?

    我想測(cè)量 AURIX TriCore? TC3xx 項(xiàng)目的函數(shù)調(diào)用的堆棧使用情況。 我不知道該怎么做。 我知道事實(shí)上作為硬件我只有一個(gè) TC375 lite 開發(fā)板,沒有 BlueBox 或任何
    發(fā)表于 08-08 07:28

    OBC/DC-DC/BMS/熱管理/智能座艙磁性元件使用情況與要求

    理/智能座艙等功能模塊中磁性元件使的用情況與性能要求,《磁性元件與電源》采訪了敦源電子研發(fā)總監(jiān)汪洪偉,為我們一一揭秘。 OBC/DC-DC/BMS/熱管理/智能座艙磁性元件使用情況 隨著新能源汽車向高集成化、智能化方向加速發(fā)展,磁性元件作為電子系統(tǒng)的“隱
    的頭像 發(fā)表于 07-08 14:05 ?963次閱讀
    OBC/DC-DC/BMS/熱管理/智能座艙磁性元件<b class='flag-5'>使用情況</b>與要求

    請(qǐng)問如何優(yōu)化OpenVINO?工具套件中的內(nèi)存使用?

    運(yùn)行OpenVINO?推斷時(shí)找不到優(yōu)化內(nèi)存使用情況的方法。
    發(fā)表于 06-25 06:56

    如何針對(duì)學(xué)校水電預(yù)付費(fèi)需求進(jìn)行一體化管理

    管理和數(shù)據(jù)分析等功能。以下是對(duì)學(xué)校水電預(yù)付費(fèi)系統(tǒng)的詳細(xì)介紹:安科瑞+武陳燕+17269603655 一、系統(tǒng)功能 實(shí)時(shí)監(jiān)控,實(shí)現(xiàn)預(yù)付費(fèi) 系統(tǒng)通過安裝智能水電表,實(shí)時(shí)監(jiān)測(cè)校園各個(gè)區(qū)域的水電使用情況,確保數(shù)據(jù)的準(zhǔn)確性和
    的頭像 發(fā)表于 06-04 16:29 ?532次閱讀
    如何針對(duì)學(xué)校水電預(yù)付費(fèi)需求進(jìn)行一體化管理

    S32G3有沒有辦法從.map文件確定SRAM使用情況

    我有 NXP S32G3 板。我有 .map 文件。有沒有辦法從 .map 文件確定 SRAM 使用情況。 非常感謝幫助。
    發(fā)表于 04-08 06:00