日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁(yè) > 單片機(jī) > 程序喵大人

項(xiàng)目背景

現(xiàn)實(shí)困境

做C、C++開(kāi)發(fā)的朋友應(yīng)該都知道,C、C++中的內(nèi)存是手動(dòng)管理的,手動(dòng)內(nèi)存管理是一把雙刃劍,雖然提供了極致性能,但可能由于開(kāi)發(fā)者的一點(diǎn)點(diǎn)疏忽,就導(dǎo)致內(nèi)存泄露。據(jù)非官方統(tǒng)計(jì),全球每年因內(nèi)存泄露導(dǎo)致的系統(tǒng)崩潰事故超過(guò)120萬(wàn)次。

C、C++開(kāi)發(fā)者面臨以下痛點(diǎn)時(shí)經(jīng)常束手無(wú)策:

  • 幽靈式內(nèi)存泄露:程序運(yùn)行數(shù)天后,出現(xiàn)內(nèi)存耗盡,因?yàn)槌绦蚴且稽c(diǎn)點(diǎn)釋放的,不太容易發(fā)現(xiàn)具體問(wèn)題所在。
  • 多線程競(jìng)態(tài)問(wèn)題:死鎖導(dǎo)致的服務(wù)假死,并且不好復(fù)現(xiàn)。

現(xiàn)有方案的局限

傳統(tǒng)工具,Asan、valgrind、gdb功能非常強(qiáng)大,可以檢測(cè)基本的問(wèn)題,但也恰恰是因?yàn)楣δ芴^(guò)豐富且強(qiáng)大,所以性能損耗非常高,無(wú)法用于線上環(huán)境,并且難以捕獲隨機(jī)出現(xiàn)的死鎖場(chǎng)景。

項(xiàng)目目標(biāo)

開(kāi)發(fā)一個(gè)零侵入、高性能、全維度的運(yùn)行時(shí)診斷系統(tǒng):

  • 內(nèi)存監(jiān)控:可以實(shí)時(shí)追蹤每個(gè)內(nèi)存塊的完整生命周期。
  • 死鎖檢測(cè):可以檢測(cè)出死鎖,并能檢測(cè)出哪個(gè)線程的哪幾把鎖出現(xiàn)了死鎖,哪個(gè)線程由于等待的哪把鎖而出現(xiàn)的死鎖,可以精確關(guān)聯(lián)源代碼位置。
  • 內(nèi)存泄露檢測(cè):可以檢測(cè)出具體哪塊內(nèi)存出現(xiàn)了泄露,并精確關(guān)聯(lián)到源代碼位置。

項(xiàng)目介紹

整體架構(gòu)如圖:

內(nèi)存檢測(cè)

直接看代碼,下面代碼會(huì)發(fā)生內(nèi)存泄露:

extern "C"int TestMemoryLeak() {  int *ptr = (int *)malloc(100);  printf("TestMemoryLeak: %p\n", ptr);  free(ptr);  return 0; }  extern"C"int TestMemoryLeak2() {  int *ptr = (int *)malloc(110);  printf("TestMemoryLeak2: %p\n", ptr);  int *p = newint[10];   auto q = std::make_unique<int>(10);  return 0; } 

集成了工具后:

int main() {  OpenDynamicExample();  MemoryDetector detect("/mnt/d/project/camping/detector/libdynamic_example.so");   detect.StartTracking();   UseDynamicExample();   detect.StopTracking(); // 會(huì)打印 lib1.so 的內(nèi)存使用情況  CloseDynamicExample();   return 0; } 

直接就可以檢測(cè)這個(gè)動(dòng)態(tài)庫(kù)的內(nèi)存情況:

本工具可以檢測(cè)出程序申請(qǐng)了多少內(nèi)存,申請(qǐng)了多少塊內(nèi)存,以及具體哪里發(fā)生了內(nèi)存泄露,可以精確到具體的源代碼位置。

它不僅可以檢測(cè)malloc、free申請(qǐng)和釋放的內(nèi)存,即便是C++的new、delete、new[]delete[]、std::make_unique、std::make_shared,也可以,不管程序是通過(guò)哪種方式申請(qǐng)和釋放的內(nèi)存,只要發(fā)生了內(nèi)存泄露,工具都可以檢測(cè)到。

整體采用Hook方案,基本流程如圖:

死鎖檢測(cè)

看這段發(fā)生死鎖的代碼:

static void *ThreadFunc1(void *) {  pthread_mutex_lock(&mutexA);  std::cout << "Thread 1: Locked A\n";  sleep(1);   std::cout << "Thread 1: Trying to lock B\n";  pthread_mutex_lock(&mutexB);  std::cout << "Thread 1: Locked B\n";   pthread_mutex_unlock(&mutexB);  pthread_mutex_unlock(&mutexA);  return nullptr; }  static void *ThreadFunc2(void *) {  pthread_mutex_lock(&mutexB);  std::cout << "Thread 2: Locked B\n";  sleep(1);   std::cout << "Thread 2: Trying to lock A\n";  pthread_mutex_lock(&mutexA);  std::cout << "Thread 2: Locked A\n";   pthread_mutex_unlock(&mutexA);  pthread_mutex_unlock(&mutexB);  return nullptr; }  static void *ThreadFunc3(void *) {  std::mutex mtx;  std::cout << "Thread 3: Trying to lock mutex\n";  mtx.lock();  std::cout << "Thread 3: Locked mutex\n";  sleep(1);  mtx.unlock();  return nullptr; }  // 導(dǎo)出的函數(shù),用于創(chuàng)建死鎖場(chǎng)景 static void CreateDeadlock() {  pthread_t t1, t2, t3;  pthread_attr_t attr;   // 初始化線程屬性  pthread_attr_init(&attr);  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);   // 創(chuàng)建分離的線程  pthread_create(&t1, &attr, ThreadFunc1, nullptr);  pthread_create(&t2, &attr, ThreadFunc2, nullptr);  pthread_create(&t3, &attr, ThreadFunc3, nullptr);   // 銷毀線程屬性  pthread_attr_destroy(&attr);   // 等待一段時(shí)間讓死鎖發(fā)生  sleep(3); } 

從代碼中可以看到,Thread1Thread2會(huì)發(fā)生死鎖,集成工具后:

LockHook lock_hook("./libdynamic_example.so"); if (!lock_hook.StartTracking()) {  std::cerr << "Failed to start lock tracking\n";  dlclose(handle);  return 1; } lock_hook.StopTracking(); 

結(jié)果如圖:

工具可以檢測(cè)出哪里發(fā)生了死鎖、哪個(gè)線程持有了哪把鎖、以及哪把鎖被哪個(gè)線程持有了。

且無(wú)論你是通過(guò)pthread_lock、還是mutex.lock、還是unique_lock或者lock_guard,只要發(fā)生了死鎖,工具都可以檢測(cè)到,并且可以定位到源代碼位置。

整體也采用Hook方案,流程如圖所示:

項(xiàng)目收獲

項(xiàng)目代碼量不大,核心代碼大概2000行左右,但涉及到的技術(shù)內(nèi)容非常豐富且硬核。

通過(guò)本項(xiàng)目,你可以收獲到:

  1. 提升C、C++的編碼能力、內(nèi)存管理黑科技、多線程調(diào)試技巧
  2. ELF 文件結(jié)構(gòu),包括section 和 segment的概念以及具體作用等。
  3. 編譯鏈接技術(shù),動(dòng)態(tài)鏈接與靜態(tài)鏈接的區(qū)別。
  4. 動(dòng)態(tài)鏈接與加載,了解動(dòng)態(tài)鏈接器如何在運(yùn)行時(shí)解析符號(hào)和加載動(dòng)態(tài)庫(kù)。
  5. PLT機(jī)制,與GOT之間的關(guān)系。
  6. GOT作用,如何存儲(chǔ)動(dòng)態(tài)鏈接的函數(shù)地址。
  7. 函數(shù)調(diào)用約定,不同架構(gòu)下的函數(shù)調(diào)用約定。
  8. 內(nèi)存保護(hù)機(jī)制,了解Linux上的內(nèi)存保護(hù)機(jī)制(如DEP、ASLR),以及如何影響代碼注入和鉤子技術(shù)。
  9. 調(diào)試工具,使用工具(如objdump、gdb)分析二進(jìn)制文件,理解如何定位和修改PLT。
  10. Hook技術(shù),如何將自定義代碼注入到目標(biāo)進(jìn)程中,以實(shí)現(xiàn)鉤子功能。
  11. 鉤子的安全性,鉤子技術(shù)是否有風(fēng)險(xiǎn)。
  12. 編寫(xiě)和測(cè)試,學(xué)習(xí)如何編寫(xiě)鉤子代碼,并在不同環(huán)境中進(jìn)行測(cè)試。
  13. 鉤子技術(shù)的性能分析。
  14. 動(dòng)態(tài)庫(kù)的加載過(guò)程,詳細(xì)了解共享庫(kù)的加載過(guò)程,包括如何在運(yùn)行時(shí)解析依賴關(guān)系。
  15. 符號(hào)解析與重定位,符號(hào)解析的機(jī)制以及重定位表的作用。
  16. 內(nèi)存管理和分配機(jī)制,內(nèi)存管理機(jī)制,特別是如何安全地分配和修改內(nèi)存以實(shí)現(xiàn)鉤子。
  17. 內(nèi)存泄漏檢測(cè)技術(shù),理解了內(nèi)存管理分配機(jī)制,可以實(shí)現(xiàn)檢測(cè)內(nèi)存泄漏的能力。
  18. 鎖機(jī)制,鎖的底層實(shí)現(xiàn)原理,如何實(shí)現(xiàn)加解鎖相關(guān)的鉤子。
  19. 死鎖檢測(cè)技術(shù),理解了加解鎖的底層機(jī)制,可以實(shí)現(xiàn)檢測(cè)程序是否產(chǎn)生了死鎖。
  20. 編譯鏈接技術(shù),Debug模式和Release模式的區(qū)別。
  21. 符號(hào)管理機(jī)制,調(diào)試符號(hào)信息的作用。
  22. 調(diào)用棧技術(shù),如何獲取線程的調(diào)用堆棧,如何根據(jù)地址解析出對(duì)應(yīng)代碼函數(shù)名和行號(hào)。


本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
關(guān)閉