記憶體泄漏檢測工具Valgrind

来源:http://www.cnblogs.com/dongdongwq/archive/2016/04/11/5377343.html
-Advertisement-
Play Games

1概述 1.1 介紹 Valgrind是一套Linux下,開放源代碼(GPL V2)的模擬調試工具的集合。Valgrind由內核(core)以及基於內核的其他調試工具組成。內核類似於一個框架(framework),它模擬了一個CPU環境,並提供服務給其他工具;而其他工具則類似於插件 (plug-in ...


1概述

1.1 介紹

Valgrind是一套Linux下,開放源代碼(GPL V2)的模擬調試工具的集合。Valgrind由內核(core)以及基於內核的其他調試工具組成。內核類似於一個框架(framework),它模擬了一個CPU環境,並提供服務給其他工具;而其他工具則類似於插件 (plug-in),利用內核提供的服務完成各種特定的記憶體調試任務。Valgrind的體繫結構如下圖所示:

 

圖1

1.2 工具

Valgrind的最新版是3.11.0,它一般包含下列工具: 

1.Memcheck 

    最常用的工具,用來檢測程式中出現的記憶體問題,所有對記憶體的讀寫都會被檢測到,一切對malloc()/free()/new/delete的調用都會被捕獲。所以,它能檢測以下問題: 

    對未初始化記憶體的使用; 

    讀/寫釋放後的記憶體塊; 

    讀/寫超出malloc分配的記憶體塊; 

    讀/寫不適當的棧中記憶體塊; 

    記憶體泄漏,指向一塊記憶體的指針永遠丟失; 

    不正確的malloc/free或new/delete匹配; 

    memcpy()相關函數中的dst和src指針重疊。 

2.Callgrind 

    和gprof類似的分析工具,但它對程式的運行觀察更是入微,能給我們提供更多的信息。和gprof不同,它不需要在編譯源代碼時附加特殊選項,但加上調試選項是推薦的。Callgrind收集程式運行時的一些數據,建立函數調用關係圖,還可以有選擇地進行cache模擬。在運行結束時,它會把分析數據寫入一個文件。callgrind_annotate可以把這個文件的內容轉化成可讀的形式。 

3.Cachegrind 

    Cache分析器,它模擬CPU中的一級緩存I1,Dl和二級緩存,能夠精確地指出程式中cache的丟失和命中。如果需要,它還能夠為我們提供cache丟失次數,記憶體引用次數,以及每行代碼,每個函數,每個模塊,整個程式產生的指令數。這對優化程式有很大的幫助。 

4.Helgrind 

    它主要用來檢查多線程程式中出現的競爭問題。Helgrind尋找記憶體中被多個線程訪問,而又沒有一貫加鎖的區域,這些區域往往是線程之間失去同步的地方,而且會導致難以發掘的錯誤。Helgrind實現了名為“Eraser”的競爭檢測演算法,並做了進一步改進,減少了報告錯誤的次數。不過,Helgrind仍然處於實驗階段。 

5.Massif 

    堆棧分析器,它能測量程式在堆棧中使用了多少記憶體,告訴我們堆塊,堆管理塊和棧的大小。Massif能幫助我們減少記憶體的使用,在帶有虛擬記憶體的現代系統中,它還能夠加速我們程式的運行,減少程式停留在交換區中的幾率。 

此外,lackey和nulgrind也會提供。Lackey是小型工具,很少用到;Nulgrind只是為開發者展示如何創建一個工具。

1.3 原理

Memcheck 能夠檢測出記憶體問題,關鍵在於其建立了兩個全局表。Valid-Value 表

對於進程的整個地址空間中的每一個位元組(byte),都有與之對應的 8 個 bits;對於CPU的每個寄存器,也有一個與之對應的bit向量。這些bits負責記錄該位元組或者寄存器值是否具有有效的、已初始化的值。

Valid-Address 表

對於進程整個地址空間中的每一個位元組(byte),還有與之對應的1個bit,負責記錄該地址是否能夠被讀寫。

檢測原理:

當要讀寫記憶體中某個位元組時,首先檢查這個位元組對應的 A bit。如果該A bit顯示該位置是無效位置,memcheck則報告讀寫錯誤。

內核(core)類似於一個虛擬的 CPU 環境,這樣當記憶體中的某個位元組被載入到真實的 CPU 中時,該位元組對應的 V bit 也被載入到虛擬的 CPU 環境中。一旦寄存器中的值,被用來產生記憶體地址,或者該值能夠影響程式輸出,則 memcheck 會檢查對應的V bits,如果該值尚未初始化,則會報告使用未初始化記憶體錯誤。

2 安裝使用

2.1安裝

從官網http://www.valgrind.org下載最新版本(當前3.11)

#tar xvf valgrind-3.11.1.tar.bz2
#cd valgrind-3.11.1
#./configure --prefix=/usr/local/valgrind--指定安裝目錄
#make
#make install

2.2 命令介紹

用法:valgrind[options] prog-and-args [options]: 常用選項,適用於所有Valgrind工具

  1. -tool=<name> 最常用的選項。運行 valgrind中名為toolname的工具。預設memcheck。
  2. h –help 顯示幫助信息。
  3. -version 顯示valgrind內核的版本,每個工具都有各自的版本。
  4. q –quiet 安靜地運行,只列印錯誤信息。
  5. v –verbose 更詳細的信息, 增加錯誤數統計。
  6. -trace-children=no|yes 跟蹤子線程? [no]
  7. -track-fds=no|yes 跟蹤打開的文件描述?[no]
  8. -time-stamp=no|yes 增加時間戳到LOG信息? [no]
  9. -log-fd=<number> 輸出LOG到描述符文件 [2=stderr]
  10. -log-file=<file> 將輸出的信息寫入到filename.PID的文件里,PID是運行程式的進行ID
  11. -log-file-exactly=<file> 輸出LOG信息到 file
  12. -log-file-qualifier=<VAR> 取得環境變數的值來做為輸出信息的文件名。 [none]
  13. -log-socket=ipaddr:port 輸出LOG到socket ,ipaddr:port

LOG信息輸出:

  1. -xml=yes 將信息以xml格式輸出,只有memcheck可用
  2. -num-callers=<number> show <number> callers in stack traces [12]
  3. -error-limit=no|yes 如果太多錯誤,則停止顯示新錯誤? [yes]
  4. -error-exitcode=<number> 如果發現錯誤則返回錯誤代碼 [0=disable]
  5. -db-attach=no|yes 當出現錯誤,valgrind會自動啟動調試器gdb。[no]
  6. -db-command=<command> 啟動調試器的命令行選項[gdb -nw %f %p]

適用於Memcheck工具的相關選項:

  1. -leak-check=no|summary|full 要求對leak給出詳細信息? [summary]
  2. -leak-resolution=low|med|high how much bt merging in leak check [low]
  3. -show-reachable=no|yes show reachable blocks in leak check? [no]

3 應用實踐

    下麵通過介紹幾個範例來說明如何使用Memcheck (其他工具暫不涉及,感興趣可以交流),示例僅供參考,更多用途可在實際應用中不斷探索。

3.1數組越界/記憶體未釋放

#include<stdlib.h>

void k(void)

{

int *x = malloc(8 * sizeof(int));

x[9] = 0;               //數組下標越界

}                         //記憶體未釋放

 

int main(void)

{

    k();

return 0;

}

1)編譯程式test.c

gcc -Wall test.c -g -o test#Wall提示所有告警,-g gdb,-o輸出

2)使用Valgrind檢查程式BUG

valgrind --tool=memcheck --leak-check=full ./test

#--leak-check=full 所有泄露檢查

3) 運行結果如下:

==2989== Memcheck, a memory error detector

==2989== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward

et al.

==2989== Using Valgrind-3.8.1 and LibVEX; rerun with -h for

copyright info

==2989== Command: ./test

==2989==

==2989==  Invalid write of size 4

==2989==    at 0x4004E2: k (test.c:5)

==2989==    by 0x4004F2: main (test.c:10)

==2989==  Address 0x4c27064 is 4 bytes after a block of size 32 alloc'd

==2989==    at 0x4A06A2E: malloc (vg_replace_malloc.c:270)

==2989==    by 0x4004D5: k (test.c:4)

==2989==    by 0x4004F2: main (test.c:10)

==2989==

==2989==

==2989== HEAP SUMMARY:

==2989==     in use at exit: 32 bytes in 1 blocks

==2989==   total heap usage: 1 allocs, 0 frees, 32 bytes allocated

==2989==

==2989== 32 bytes in 1 blocks are definitely lost in loss record 1

of 1

==2989==    at 0x4A06A2E: malloc (vg_replace_malloc.c:270)

==2989==    by 0x4004D5: k (test.c:4)

==2989==    by 0x4004F2: main (test.c:10)

==2989==

==2989== LEAK SUMMARY:

==2989==    definitely lost: 32 bytes in 1 blocks

==2989==    indirectly lost: 0 bytes in 0 blocks

==2989==      possibly lost: 0 bytes in 0 blocks

==2989==    still reachable: 0 bytes in 0 blocks

==2989==suppressed: 0 bytes in 0 blocks

==2989==

==2989== For counts of detected and suppressed errors, rerun with: -v

==2989== ERROR SUMMARY: 2 errors from 2 contexts

(suppressed: 6 from 6)

3.2記憶體釋放後讀寫

#include <stdio.h>

#include <stdlib.h>

 

int main(void)

{

char *p = malloc(1);    //分配

*p = 'a';

 

char c = *p;

 

printf("\n [%c]\n",c);

 

free(p);         //釋放

    c = *p;         //取值

return 0;

}

1)編譯程式t2.c

gcc -Wall t2.c -g -o t2 

2)使用Valgrind檢查程式BUG

valgrind --tool=memcheck --leak-check=full ./t2

3) 運行結果如下:

      ==3058== Memcheck, a memory error detector

==3058== Copyright (C) 2002-2012, and GNU GPL'd, by Julian

Seward et al.

==3058== Using Valgrind-3.8.1 and LibVEX; rerun with -h

for copyright info

==3058== Command: ./t2

==3058==

 

      [a]

==3058== Invalid read of size 1

==3058==    at 0x4005A3: main (t2.c:14)

==3058==  Address 0x4c27040 is 0 bytes inside a block of size

1 free'd

==3058==    at 0x4A06430: free (vg_replace_malloc.c:446)

==3058==    by 0x40059E: main (t2.c:13)

==3058==

==3058==

==3058== HEAP SUMMARY:

==3058==     in use at exit: 0 bytes in 0 blocks

==3058==   total heap usage: 1 allocs, 1 frees, 1 bytes allocated

==3058==

==3058== All heap blocks were freed -- no leaks are possible

==3058==

==3058== For counts of detected and suppressed errors, rerun with:

 -v

==3058== ERROR SUMMARY: 1 errors from 1 contexts

(suppressed: 6 from 6)

從上輸出內容可以看到,Valgrind檢測到無效的讀取操作然後輸出“Invalid read of size 1”。

3.3無效讀寫

#include <stdio.h>

#include <stdlib.h>

 

int main(void)

{

   char *p = malloc(1);    //分配1位元組

   *p = 'a';

   char c = *(p+1);         //地址加1

   printf("\n [%c]\n",c); 

   free(p);

   return 0;

}

1)編譯程式t3.c

gcc -Wall t3.c -g -o t3 

2)使用Valgrind檢查程式BUG

valgrind --tool=memcheck --leak-check=full ./t3

3) 運行結果如下:

==3128== Memcheck, a memory error detector

==3128== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.

==3128== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info

==3128== Command: ./t3

==3128==

==3128==  Invalid read of size 1        #無效讀取

==3128==at 0x400579: main (t3.c:9)

==3128==Address 0x4c27041 is 0 bytes after a block of size 1 alloc'd

==3128==at 0x4A06A2E: malloc (vg_replace_malloc.c:270)

==3128==by 0x400565: main (t3.c:6)

==3128==

 []

==3128==

==3128== HEAP SUMMARY:

==3128==in use at exit: 0 bytes in 0 blocks

==3128==total heap usage: 1 allocs, 1 frees, 1 bytes allocated

==3128==

==3128== All heap blocks were freed -- no leaks are possible

==3128==

==3128== For counts of detected and suppressed errors, rerun with: -v

==3128== ERROR SUMMARY: 1 errors from 1 contexts

(suppressed: 6 from 6)

3.4記憶體泄露

#include <stdio.h>

#include <stdlib.h>

 

int main(void)

{

int *p = malloc(1);

*p = 'x';

char c = *p;

printf("%c\n",c);        //申請後未釋放

    return 0;

}

1)編譯程式t4.c

gcc -Wall t4.c -g -o t4 

2)使用Valgrind檢查程式BUG

valgrind --tool=memcheck --leak-check=full ./t4

3) 運行結果如下:

==3221== Memcheck, a memory error detector

==3221== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.

==3221== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info

==3221== Command: ./t4

==3221==

==3221== Invalid write of size 4

==3221==at 0x40051E: main (t4.c:7)

==3221==Address 0x4c27040 is 0 bytes inside a block of size 1 alloc'd

==3221==at 0x4A06A2E: malloc (vg_replace_malloc.c:270)

==3221==by 0x400515: main (t4.c:6)

==3221==

==3221== Invalid read of size 4

==3221==at 0x400528: main (t4.c:8)

==3221==Address 0x4c27040 is 0 bytes inside a block of size 1 alloc'd

==3221==at 0x4A06A2E: malloc (vg_replace_malloc.c:270)

==3221==by 0x400515: main (t4.c:6)

==3221==

x

==3221==

==3221== HEAP SUMMARY:

==3221==in use at exit: 1 bytes in 1 blocks

==3221==total heap usage: 1 allocs, 0 frees, 1 bytes allocated

==3221==

==3221== 1 bytes in 1 blocks are definitely lost in loss record 1 of 1

==3221==at 0x4A06A2E: malloc (vg_replace_malloc.c:270)

==3221==by 0x400515: main (t4.c:6)

==3221==

==3221== LEAK SUMMARY:

==3221==definitely lost: 1 bytes in 1 blocks

==3221==indirectly lost: 0 bytes in 0 blocks

==3221==      possibly lost: 0 bytes in 0 blocks

==3221==still reachable: 0 bytes in 0 blocks

==3221==         suppressed: 0 bytes in 0 blocks

==3221==

==3221== For counts of detected and suppressed errors, rerun with: -v

==3221== ERROR SUMMARY: 3 errors from 3 contexts

(suppressed: 6 from 6)

從檢查結果看,可以發現記憶體泄露。

3.5記憶體多次釋放

#include <stdio.h>

#include <stdlib.h>

int main(void) 

    char *p;

    p=(char *)malloc(100);    

    if(p)

        printf("Memory Allocated at: %s/n",p); 

    else

        printf("Not Enough Memory!/n"); 

    free(p);                           //重覆釋放

    free(p);

    free(p);

    return 0;

1)編譯程式t5.c

gcc -Wall t5.c -g -o t5 

2)使用Valgrind檢查程式BUG

valgrind --tool=memcheck --leak-check=full ./t5

3) 運行結果如下:

==3294== Memcheck, a memory error detector

==3294== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward

et al.

==3294== Using Valgrind-3.8.1 and LibVEX; rerun with -h for

copyright info

==3294== Command: ./t5

==3294==

==3294== Conditional jump or move depends on uninitialised value(s)

==3294==    at 0x3CD4C47E2C: vfprintf (in /lib64/libc-2.12.so)

==3294==    by 0x3CD4C4F189: printf (in /lib64/libc-2.12.so)

==3294==    by 0x400589: main (t5.c:9)

==3294==

==3294== Invalid free() / delete / delete[] / realloc()

==3294==    at 0x4A06430: free (vg_replace_malloc.c:446)

==3294==    by 0x4005B5: main (t5.c:13)

==3294==  Address 0x4c27040 is 0 bytes inside a block of size

100 free'd

==3294==    at 0x4A06430: free (vg_replace_malloc.c:446)

==3294==    by 0x4005A9: main (t5.c:12)

==3294==

==3294== Invalid free() / delete / delete[] / realloc()

==3294==    at 0x4A06430: free (vg_replace_malloc.c:446)

==3294==    by 0x4005C1: main (t5.c:14)

==3294==  Address 0x4c27040 is 0 bytes inside a block of size

100 free'd

==3294==    at 0x4A06430: free (vg_replace_malloc.c:446)

==3294==    by 0x4005A9: main (t5.c:12)

==3294==

Memory Allocated at: /n==3294==

==3294== HEAP SUMMARY:

==3294==     in use at exit: 0 bytes in 0 blocks

==3294==   total heap usage: 1 allocs, 3 frees, 100 bytes allocated

從上面的輸出可以看到(標註), 該功能檢測到我們對同一個指針調用了3次釋放記憶體操作。

3.6記憶體動態管理

常見的記憶體分配方式分三種:靜態存儲,棧上分配,堆上分配。全局變數屬於靜態存儲,它們是在編譯時就被分配了存儲空間,函數內的局部變數屬於棧上分配,而最靈活的記憶體使用方式當屬堆上分配,也叫做記憶體動態分配了。常用的記憶體動態分配函數包括:malloc, alloc, realloc, new等,動態釋放函數包括free, delete。

一旦成功申請了動態記憶體,我們就需要自己對其進行記憶體管理,而這又是最容易犯錯誤的。下麵的一段程式,就包括了記憶體動態管理中常見的錯誤。

#include <stdio.h>

#include <stdlib.h>

int main(int argc,char *argv[])

{

int i;

char* p = (char*)malloc(10);

char* pt=p;

for(i = 0;i < 10;i++)

    {

p[i] = 'z';

    }

free(p);

pt[1] = 'x';

free(pt);

return 0;

}

1)編譯程式t6.c

gcc -Wall t6.c -g -o t6 

2)使用Valgrind檢查程式BUG

valgrind --tool=memcheck --leak-check=full ./t6

3) 運行結果如下:

==3380== Memcheck, a memory error detector

==3380== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.

==3380== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info

==3380== Command: ./t6

==3380==

==3380==  Invalid write of size 1

==3380==at 0x40055C: main (t6.c:14)

==3380==Address 0x4c27041 is 1 bytes inside a block of size 10 free'd

==3380==at 0x4A06430: free (vg_replace_malloc.c:446)

==3380==by 0x400553: main (t6.c:13)

==3380==

==3380==  Invalid free() / delete / delete[] / realloc()

==3380==at 0x4A06430: free (vg_replace_malloc.c:446)

==3380==by 0x40056A: main (t6.c:15)

==3380==Address 0x4c27040 is 0 bytes inside a block of size 10 free'd

==3380==at 0x4A06430: free (vg_replace_malloc.c:446)

==3380==by 0x400553: main (t6.c:13)

==3380==

==3380==

==3380== HEAP SUMMARY:

==3380==in use at exit: 0 bytes in 0 blocks

==3380==total heap usage: 1 allocs, 2 frees, 10 bytes allocated

   申請記憶體在使用完成後就要釋放。如果沒有釋放,或少釋放了就是記憶體泄露;多釋放也會產生問題。上述程式中,指針p和pt指向的是同一塊記憶體,卻被先後釋放兩次。系統會在堆上維護一個動態記憶體鏈表,如果被釋放,就意味著該塊記憶體可以繼續被分配給其他部分,如果記憶體被釋放後再訪問,就可能覆蓋其他部分的信息,這是一種嚴重的錯誤,上述程式第14行中就在釋放後仍然寫這塊記憶體。

    輸出結果顯示,第13行分配和釋放函數不一致;第14行發生非法寫操作,也就是往釋放後的記憶體地址寫值;第15行釋放記憶體函數無效。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Atitit.跨語言異常轉換機制 java c# php到js的異常轉換 1. bizEx 直接抓取,然後js catchEX1 2. Chkec runtimeEx1 3. Other異常。。Js convet 2 js err,then throw ...2 1. bizEx 直接抓取,然後js ...
  • atitit.React 優缺點 相比angular react是最靠譜的web ui組件化方案了 1. React的組件化才是web ui部件的正確方向1 1.1. 組件化集成html ,css,js自我包含一體化,方便復用。1 1.2. 相比angular。Js方便好用1 2. React的問題 ...
  • 一、 數據定義語言(ddl) 數據定義語言ddl(data definition language)用於改變資料庫結構,包括創建、更改和刪除資料庫對象。 用於操縱表結構的數據定義語言命令有: create table alter table truncate table drop table eg、 ...
  • mysql的性能優化無法一蹴而就,必須一步一步慢慢來,從各個方面進行優化,最終性能就會有大的提升。 Mysql資料庫的優化技術 對mysql優化是一個綜合性的技術,主要包括 表的設計合理化(符合3NF) 添加適當索引(index) [四種: 普通索引、主鍵索引、唯一索引unique、全文索引] 分表 ...
  • 在我們使用查詢語句的時候,經常要返回前幾條或者中間某幾行數據,這個時候怎麼辦呢?不用擔心,Mysql已經為我們提供了這樣一個功能。 SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset SELECT * FROM table LI ...
  • 今晚繼續進行Sql效能問題的分享,今天主要是一些具體的sql優化方法和思路分享,若看過後你也有其他想法,歡迎一起探討,好了,進入今天的主題。 針對性地對一些耗資源嚴重的具體應用進行優化 出現效能問題時,首先要做的是什麼?這個問題我問過不少同事,有人說憑經驗對出問題的sql進行優化,如我們一般說的要合 ...
  • 今天本想將之前的一個資料庫easy.sql用圖形化工具Navicat導入的,開始是用“運行SQL文件”導入,結果是“queries successfully”啥的,去查是否導表成功,一看並沒有。 結果失望之餘,把那個資料庫和伺服器全刪了,再建一個和要導入的資料庫同名的資料庫名,意外的是重啟後資料庫就 ...
  • 1唯一約束unique和主鍵key的區別? 1、什麼是數據的存儲引擎? 存儲引擎就是如何存儲數據、如何為存儲的數據建立索引和如何更新、查詢數據等技術的實現方法。因為在關係資料庫中數據的存儲是以表的形式存儲的,所以存儲引擎也可以稱為表類型(即存儲和操作該表的類型),在Oracle和SQL Server ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...