亚洲av成人精品日韩一区,97久久久精品综合88久久,玩弄japan白嫩少妇hd,亚洲av片不卡无码久久,玩弄人妻少妇500系列

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

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

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

線程內(nèi)存泄漏問(wèn)題的定位

科技綠洲 ? 來(lái)源:Linux開(kāi)發(fā)架構(gòu)之路 ? 作者:Linux開(kāi)發(fā)架構(gòu)之路 ? 2023-11-13 11:38 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

記錄一個(gè)關(guān)于線程內(nèi)存泄漏問(wèn)題的定位過(guò)程,以及過(guò)程中的收獲。

1. 初步定位

是否存在內(nèi)存泄漏:想到內(nèi)存泄漏,首先查看/proc/meminfo,通過(guò)/proc/meminfo可以看出總體內(nèi)存在下降。確定內(nèi)存泄漏確實(shí)存在。top中可以顯示多種形式內(nèi)存,進(jìn)而可以判斷是那種泄漏。比如vss/rss/pss等。

確定哪個(gè)進(jìn)程內(nèi)存泄漏:通過(guò)top即可查看到是哪個(gè)進(jìn)程在泄漏。至此基本可以確定到哪個(gè)進(jìn)程。

確定進(jìn)程泄漏內(nèi)存類(lèi)型:然后查看進(jìn)程的/proc//maps,通過(guò)maps可以看出泄漏的內(nèi)存類(lèi)型(堆、棧、匿名內(nèi)存等等),有時(shí)候運(yùn)氣好可以直接判斷泄漏點(diǎn)。

如果是slab:可以通過(guò)/proc/slabinfo,可以看出進(jìn)程的動(dòng)態(tài)變化情況。如果確定是哪一個(gè)slab,那么可以在/sys/kernel/slab//alloc_calls和free_calls中直接找到調(diào)用點(diǎn)。當(dāng)然看到的是內(nèi)核空間的函數(shù)。

使用mcheck():可以檢查malloc/free造成的泄漏問(wèn)題。

通過(guò)如下腳本,然后對(duì)每次抓取內(nèi)容進(jìn)行Beyond Compare。每個(gè)一定周期抓取相關(guān)內(nèi)存消耗信息。

#!/bin/bash
echo > mem_log.txt
while true
do
    cat /proc/meminfo > >mem_log.txt
    cat /proc/< pid >/maps > >mem_log.txt
    cat /proc/slabinfo > >mem_log.txt
    sleep 240
done

當(dāng)然還有其他工具gcc Sanitier、Valgrind等等,由于嵌入式環(huán)境受限未能使用。

2. 深入定位

同步查看meminfo、maps、slabinfo,發(fā)覺(jué)進(jìn)程虛擬內(nèi)存損耗很快,遠(yuǎn)比系統(tǒng)MemFree損耗快。而且slabinfo沒(méi)有和maps同步損耗。

所以問(wèn)題重點(diǎn)檢查maps問(wèn)題。

00010000-00083000 r-xp 00000000 b3:11 22         /heop/package/AiApp/AiApp
00092000-00099000 rwxp 00072000 b3:11 22         /heop/package/AiApp/AiApp
00099000-00b25000 rwxp 00000000 00:00 0          [heap]
00b51000-00b52000 ---p 00000000 00:00 0 
00b52000-01351000 rwxp 00000000 00:00 0          [stack:30451]
01351000-01352000 ---p 00000000 00:00 0 
01352000-01b51000 rwxp 00000000 00:00 0 
01b51000-01b52000 ---p 00000000 00:00 0 
01b52000-02351000 rwxp 00000000 00:00 0          [stack:30432]
02351000-02352000 ---p 00000000 00:00 0 
02352000-02b51000 rwxp 00000000 00:00 0 
02b51000-02b52000 ---p 00000000 00:00 0 
...
64f55000-65754000 rwxp 00000000 00:00 0          [stack:28646]
65754000-65755000 ---p 00000000 00:00 0 
65755000-65f54000 rwxp 00000000 00:00 0          [stack:28645]
65f54000-65f55000 ---p 00000000 00:00 0 
65f55000-66754000 rwxp 00000000 00:00 0          [stack:28642]
66754000-6675a000 r-xp 00000000 00:02 5000324    /usr/lib/AiApp/gstreamer-1.0/libgsticcsink.so
6675a000-66769000 ---p 00000000 00:00 0 
...
6699f000-669a0000 rwxp 00000000 00:02 4999516    /usr/lib/AiApp/gstreamer-1.0/libgstapp.so
669a0000-66a2e000 rwxp 00000000 00:02 4999517    /usr/lib/AiApp/gstreamer-1.0/libgstlive555src.so
66a2e000-66a3e000 ---p 00000000 00:00 0 
66a3e000-66a44000 rwxp 0008e000 00:02 4999517    /usr/lib/AiApp/gstreamer-1.0/libgstlive555src.so
66a44000-66a45000 rwxp 00000000 00:00 0 
66a45000-66a46000 ---p 00000000 00:00 0 
66a46000-67245000 rwxp 00000000 00:00 0          [stack:28631]
67245000-67246000 ---p 00000000 00:00 0 
67246000-67a45000 rwxp 00000000 00:00 0          [stack:28630]
...
6b245000-6b246000 ---p 00000000 00:00 0 
6b246000-6ba45000 rwxp 00000000 00:00 0          [stack:28613]
6ba45000-6ba46000 ---p 00000000 00:00 0 
6ba46000-6c245000 rwxp 00000000 00:00 0          [stack:28610]
6c245000-71066000 rwxs 00000000 00:01 196614     /SYSV5553fc99 (deleted)
71066000-71067000 ---p 00000000 00:00 0 
71067000-71866000 rwxp 00000000 00:00 0          [stack:28609]
71866000-71867000 ---p 00000000 00:00 0 
71867000-72066000 rwxp 00000000 00:00 0          [stack:28608]
72066000-72228000 rwxs e3dc4000 00:02 6918       /dev/mmz_userdev
72228000-725ac000 rwxs e3a40000 00:02 6918       /dev/mmz_userdev
725ac000-75cac000 rwxs 00000000 00:01 131076     /SYSV6702121c (deleted)
75cac000-75e8a000 rwxs 00000000 00:01 98307      /SYSV6602121c (deleted)
75e8a000-7608e000 rwxp 00000000 00:00 0...
76eeb000-76efb000 ---p 00000000 00:00 0 
76efb000-76eff000 r-xp 000ce000 00:02 1234       /lib/libstdc++.so.6.0.20
76eff000-76f01000 rwxp 000d2000 00:02 1234       /lib/libstdc++.so.6.0.20
76f01000-76f08000 rwxp 00000000 00:00 0 
76f08000-76f0f000 r-xp 00000000 00:02 1235       /lib/ld-uClibc-0.9.33.2.so
76f1a000-76f1e000 rwxp 00000000 00:00 0 
76f1e000-76f1f000 rwxp 00006000 00:02 1235       /lib/ld-uClibc-0.9.33.2.so
76f1f000-76f20000 ---p 00000000 00:00 0...
7c720000-7cf1f000 rwxp 00000000 00:00 0          [stack:30574]
7cf1f000-7cf20000 ---p 00000000 00:00 0 
7cf20000-7e121000 rwxp 00000000 00:00 0          [stack:30575]
7eef7000-7ef18000 rwxp 00000000 00:00 0          [stack]
7efb7000-7efb8000 r-xp 00000000 00:00 0          [sigpage]
ffff0000-ffff1000 r-xp 00000000 00:00 0          [vectors]

通過(guò)多次maps對(duì)比,可以發(fā)現(xiàn)[stack:TID]類(lèi)型的內(nèi)存以及一個(gè)匿名內(nèi)存在不停增加消耗內(nèi)存。

其中[stack:TID]類(lèi)型的內(nèi)存,在內(nèi)核查找相關(guān)代碼沒(méi)有明確對(duì)應(yīng)屬性。初步判斷是線程的棧,TID表示線程id號(hào)。

所以這里應(yīng)該是某個(gè)線程泄漏。

2.1 線程棧泄漏(Joinable線程棧)

一個(gè)導(dǎo)致線程棧泄漏原因可能是對(duì)于一個(gè)Joinable線程,系統(tǒng)會(huì)創(chuàng)建線程私有的棧、threand ID、線程結(jié)束狀態(tài)等信息。

如果此線程沒(méi)有pthread_join(),那么系統(tǒng)不會(huì)對(duì)以上信息進(jìn)行回收。這就可能造成線程棧等泄漏。

確定線程棧泄漏的方法是:通過(guò)ls /proc//task | wc -l確定進(jìn)程下線程數(shù)目。然后在maps中檢查[stack:TID]數(shù)目。兩者如果不一致,則存在Joinable線程沒(méi)有調(diào)用pthread_join()造成的泄漏。

如果maps沒(méi)有[stack:TID],可以通過(guò)pmap | grep | wc -l,即通過(guò)檢查棧大小的vma數(shù)目來(lái)確定棧數(shù)目。

3. 問(wèn)題根源

通過(guò)檢查線程棧消耗與實(shí)際線程數(shù)目,發(fā)現(xiàn)兩者數(shù)目吻合。所以線程并沒(méi)有退出。也即不是由于未使用pthread_join()導(dǎo)致的內(nèi)存泄漏。

然后根據(jù)maps中[stack:TID]的pid號(hào),cat /proc//comm發(fā)現(xiàn)是同一個(gè)線程不停創(chuàng)建。但是沒(méi)有釋放。

其實(shí)通過(guò)top -H -p 和maps也可發(fā)現(xiàn)問(wèn)題,中間走了彎路。

所以問(wèn)題的根源是,進(jìn)程不停創(chuàng)建但是沒(méi)有退出造成內(nèi)存消耗殆盡。

4. 收獲

有兩個(gè)收獲,一是創(chuàng)建的pthread線程Join和Detach兩種狀態(tài)下內(nèi)存處理差別;二是在進(jìn)程maps中顯示線程棧[stack:TID]更有利于調(diào)試。

4.1 pthread線程的join和detach區(qū)別

《Avoiding memory leaks in POSIX thread programming》講到如何避免POSIX線程編程時(shí)內(nèi)存泄漏。

首先pthread_create()創(chuàng)建的線程默認(rèn)是joinable的。

對(duì)于joinable線程,系統(tǒng)會(huì)分配私有內(nèi)存存儲(chǔ)線程結(jié)束狀態(tài)、線程棧、線程ID等等資源。這些資源會(huì)一直存在,直到線程結(jié)束并且線程被其他線程joined。所以確保joinable線程資源得到釋放的兩個(gè)條件是:線程退出、被其他線程joined。

對(duì)于detached線程,如果其退出,那么系統(tǒng)會(huì)自動(dòng)回收其占用的資源。

關(guān)于joinable線程沒(méi)有被其他線程joined造成內(nèi)存泄漏的實(shí)驗(yàn)。

#include< stdio.h >
#include< pthread.h >

void run() {
   pthread_exit(0);
}

int main () {
    pthread_t thread;
    int rc;
    long count = 0;
    while(1) {
        if(rc = pthread_create(&thread, 0, run, 0) ) {
            printf("ERROR, rc is %d, so far %ld threads createdn", rc, count);
            perror("Fail:");
            return -1;
        }
        usleep(10);
        count++;
    }
    return 0;
}

輸出結(jié)果如下:

ERROR, rc is 11, so far 32751 threads created
Fail:: Cannot allocate memory

總共創(chuàng)建了32571個(gè)線程,造成內(nèi)存消耗殆盡。

通過(guò)對(duì)比中間過(guò)程的maps,可以發(fā)現(xiàn)每次增加一個(gè)8MB的棧以及一個(gè)分隔頁(yè)。

圖片

在pthread_create()之后增加pthread_join()則內(nèi)存非常穩(wěn)定。

#include< stdio.h >
#include< pthread.h >

void run() {
   pthread_exit(0);
}

int main () {
    pthread_t thread;
    int rc;
    long count = 0;
    while(1) {
        if(rc = pthread_create(&thread, 0, run, 0) ) {
            printf("ERROR, rc is %d, so far %ld threads createdn", rc, count);
            perror("Fail:");
            return -1;
        }
        pthread_join(thread, NULL);
        usleep(10);
        count++;
    }
    return 0;
}

借用文檔里面一句話(huà)總結(jié)一下:Joinable threads should be joined during programming. If you are creating joinable threads in your program, don’t forget to call pthread_join(pthread_t, void**) to recycle the private storage allocated to the thread.

調(diào)用pthread_join()將阻塞線程自己,一直等到加入的線程運(yùn)行結(jié)束。

線程可以分為兩種:joined和detached。并不是所有線程創(chuàng)建后都默認(rèn)joinable,需要顯式指定屬性。

joinable線程在創(chuàng)建后,可以通過(guò)pthread_detach()顯式分離。在分離后,不可以再合并。

如果一個(gè)線程結(jié)束運(yùn)行,但沒(méi)有被join。則它的狀態(tài)類(lèi)似進(jìn)程中的Zombie Process,即還有一部分資源沒(méi)有被回收,所以創(chuàng)建線程者應(yīng)該調(diào)用pthread_join()來(lái)等待線程結(jié)束,并可得到線程的退出代碼,回收其資源。

如果父進(jìn)程調(diào)用pthread_detach(child_thread_id)或者子進(jìn)程調(diào)用pthread_detack(pthread_self())即可將子進(jìn)程狀態(tài)設(shè)置為detached,該程序運(yùn)行結(jié)束后會(huì)自動(dòng)釋放所有資源。

4.2 關(guān)于在maps中顯示[stack:TID]

在進(jìn)程maps中顯示線程棧信息,最后在內(nèi)核中被放棄。

首先在《procfs: mark thread stack correctly in proc//maps》中,添加了[stack:TID]用于表示此vma對(duì)應(yīng)的是線程TID的stack區(qū)域。

這樣做的好處是,可以從maps中明確知道此段vma是被哪個(gè)線程使用的。

有一個(gè)壞處就是先線程非常多情況下,主線程中為了顯示[stack:TIS],開(kāi)銷(xiāo)就會(huì)很大,而實(shí)際上用處不是很大。

所以在《proc: revert /proc//maps [stack:TID] annotation》將進(jìn)程maps中的[stack:TID]刪除了,只顯示為匿名內(nèi)存。

最終再《fs/proc: Stop trying to report thread stacks》將所有[stack:TID]全部移除。

那么在沒(méi)有[stack:TID]的情況下如何斷定vma是否是線程棧呢?

首先線程棧大小可以通過(guò)ulimit -s查看,所以maps中vma大小和這個(gè)一致;并且屬性應(yīng)該是匿名的rw-p。

然后上面應(yīng)該是一頁(yè)大小作為分隔區(qū)間,分隔頁(yè)的屬性應(yīng)該是---p。

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

    關(guān)注

    5152

    文章

    19670

    瀏覽量

    317514
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4381

    瀏覽量

    64860
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    508

    瀏覽量

    20210
  • 內(nèi)存泄漏
    +關(guān)注

    關(guān)注

    0

    文章

    40

    瀏覽量

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

掃碼添加小助手

加入工程師交流群

    評(píng)論

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

    Linux上對(duì)進(jìn)程進(jìn)行內(nèi)存分析和內(nèi)存泄漏定位

    和redis進(jìn)程。當(dāng)memfree不夠時(shí),內(nèi)核會(huì)通過(guò)回寫(xiě)機(jī)制(pdflush線程)把cached和buffered內(nèi)存回寫(xiě)到后備存儲(chǔ)器,也可以通過(guò)手動(dòng)方式顯式釋放cache內(nèi)存 echo 3 >
    發(fā)表于 07-09 08:15

    AliOS Things 維測(cè)典型案例分析 —— 內(nèi)存泄漏

    使用情況全部輸出,方便定位)這是由于內(nèi)存不足,無(wú)法從系統(tǒng)內(nèi)存池中mallo出動(dòng)態(tài)內(nèi)存,出現(xiàn)這種現(xiàn)象一般有2種原因:某組件在運(yùn)行中持續(xù)分配了較大內(nèi)存
    發(fā)表于 10-17 11:29

    Executors使用不當(dāng)引起的內(nèi)存泄漏怎么解決

    是否知道了此次引起內(nèi)存泄漏的原因,其實(shí)就是因?yàn)樽枞?duì)列的容量過(guò)大?! ∪绻皇謩?dòng)的指定阻塞隊(duì)列的大小,那么它默認(rèn)是Integer.MAX_VALUE,我們的線程池只有20個(gè)線程可以處理
    發(fā)表于 12-23 17:38

    內(nèi)存泄漏定位該如何去實(shí)現(xiàn)呢

    嵌入式之內(nèi)存泄漏定位篇在嵌入式開(kāi)發(fā)中,經(jīng)常會(huì)使用malloc,free分配釋放堆內(nèi)存,當(dāng)malloc,free不配對(duì)使用時(shí),就會(huì)導(dǎo)致內(nèi)存一點(diǎn)
    發(fā)表于 12-17 07:24

    寫(xiě)了一個(gè)內(nèi)存泄漏檢查工具

    的malloc或者free的調(diào)用,記錄申請(qǐng)內(nèi)存的大小,地址,和調(diào)用的函數(shù)。以便追蹤內(nèi)存泄漏。并且開(kāi)啟一個(gè)線程,每隔一段時(shí)間監(jiān)測(cè)是否有哪個(gè)函數(shù)申請(qǐng)的內(nèi)
    發(fā)表于 12-17 08:25

    分享一種內(nèi)存泄漏定位排查技巧

    這里寫(xiě)自定義目錄標(biāo)題1.對(duì)malloc,free進(jìn)行封裝2.如何確定MALLOC_SIZE_OFFSET大小(編譯器malloc長(zhǎng)度地址偏移)3.如何監(jiān)測(cè)內(nèi)存有無(wú)泄漏4.如何快速定位內(nèi)存泄漏
    發(fā)表于 12-17 08:13

    如何編譯使用內(nèi)存泄漏定位工具

    1.我們知道有個(gè)內(nèi)存泄漏定位工具: valgrind, 非常優(yōu)秀?,F(xiàn)在已經(jīng)支持arm版本,下面看看如何編譯使用:2.下載源碼:
    發(fā)表于 12-17 08:13

    sqlite軟件包內(nèi)存泄漏如何解決?

    at function:rt_object_init, line number:358, 而從github下載的就能運(yùn)行),運(yùn)行一段時(shí)間后發(fā)現(xiàn)使用內(nèi)存不斷增大,用memtrace工具確定是操作數(shù)據(jù)庫(kù)的線程導(dǎo)致,請(qǐng)問(wèn)造成
    發(fā)表于 05-24 15:25

    解析Web內(nèi)存分析與內(nèi)存泄漏定位

    JavaScript 中開(kāi)發(fā)者并不需要手動(dòng)地為對(duì)象申請(qǐng)內(nèi)存,只需要聲明變量,JavaScript Runtime 即可以自動(dòng)地分配內(nèi)存.所謂的內(nèi)存泄漏,即是指某個(gè)對(duì)象被無(wú)意間添加了某條
    發(fā)表于 11-10 15:00 ?2600次閱讀

    ThreadLocal發(fā)生內(nèi)存泄漏的原因

    ,就可能會(huì)導(dǎo)致內(nèi)存泄漏。下面,我們將圍繞三個(gè)方面來(lái)分析 ThreadLocal 內(nèi)存泄漏的問(wèn)題 ThreadLocal 實(shí)現(xiàn)原理 ThreadLocal為什么會(huì)
    的頭像 發(fā)表于 05-05 16:23 ?3914次閱讀

    內(nèi)存泄漏的特點(diǎn)和類(lèi)型

    在計(jì)算機(jī)科學(xué)中,內(nèi)存泄漏(memory leak)指由于疏忽或錯(cuò)誤使程序未能釋放而造成不能再使用的內(nèi)存的情況。內(nèi)存泄漏并非指
    的頭像 發(fā)表于 06-20 10:58 ?3074次閱讀

    內(nèi)存泄漏問(wèn)題原理及檢視方法

    可能不少開(kāi)發(fā)者都遇到過(guò)內(nèi)存泄漏導(dǎo)致的網(wǎng)上問(wèn)題,具體表現(xiàn)為單板在現(xiàn)網(wǎng)運(yùn)行數(shù)月以后,因?yàn)?b class='flag-5'>內(nèi)存耗盡而導(dǎo)致單板復(fù)位現(xiàn)象。一方面,內(nèi)存泄漏問(wèn)題屬于比較
    的頭像 發(fā)表于 10-10 10:42 ?2844次閱讀

    什么是內(nèi)存泄漏內(nèi)存泄漏有哪些現(xiàn)象

    內(nèi)存泄漏幾乎是很難避免的,不管是老手還是新手,都存在這個(gè)問(wèn)題,甚至 Windows 與 Linux 這類(lèi)系統(tǒng)軟件也或多或少存在著內(nèi)存泄漏
    的頭像 發(fā)表于 09-05 17:24 ?1w次閱讀

    什么是內(nèi)存泄漏?如何避免JavaScript內(nèi)存泄漏

    JavaScript 代碼中常見(jiàn)的內(nèi)存泄漏的常見(jiàn)來(lái)源: 研究內(nèi)存泄漏問(wèn)題就相當(dāng)于尋找符合垃圾回收機(jī)制的編程方式,有效避免對(duì)象引用的問(wèn)題。
    發(fā)表于 10-27 11:30 ?674次閱讀
    什么是<b class='flag-5'>內(nèi)存</b><b class='flag-5'>泄漏</b>?如何避免JavaScript<b class='flag-5'>內(nèi)存</b><b class='flag-5'>泄漏</b>

    C語(yǔ)言內(nèi)存泄漏問(wèn)題原理

    內(nèi)存泄漏問(wèn)題只有在使用堆內(nèi)存的時(shí)候才會(huì)出現(xiàn),棧內(nèi)存不存在內(nèi)存泄漏問(wèn)題,因?yàn)闂?/div>
    發(fā)表于 03-19 11:38 ?848次閱讀
    C語(yǔ)言<b class='flag-5'>內(nèi)存</b><b class='flag-5'>泄漏</b>問(wèn)題原理