作為一只碼農(nóng),不僅有敲出驚人代碼本領(lǐng),更有一種與生俱來的天賦,就是在驚人的代碼中創(chuàng)造神奇的臭蟲。既然是臭蟲,就沒人喜歡了,但是既然是我們創(chuàng)造的,那我們是不是應(yīng)該有義務(wù)將其逮住,然后就呵呵呵????。。你懂的。。
臭蟲的種類繁多,能不能像物種的分類分為界,門,綱,目,科,屬,種呢,我是沒這能耐,哪位大神可以分一下。呵呵。但是有一種臭蟲是最令人討厭的,在編碼中當(dāng)屬內(nèi)存問題。下面言歸正傳。。。
內(nèi)存引起的問題可謂是一蟲??出洞千蟲??鳴啊,內(nèi)存泄漏,內(nèi)存越界,內(nèi)存安全等等,引起的問題千奇百怪,而且難以查詢。當(dāng)然像valgrind內(nèi)存檢測工具很好,但是作為嵌入式開發(fā),可就沒有如此的幸運(yùn)了,嵌入式通常的調(diào)試就是串口打印,或者各種LED燈來指示,還有就是調(diào)試大法——在線調(diào)試。如果各種調(diào)試方式都木有了,那就等死吧,因?yàn)樯系垡簿炔涣四懔恕?。?/p>
最近再開發(fā)一款產(chǎn)品,由于經(jīng)驗(yàn)不足,在臨近結(jié)尾時(shí)跳出了一只臭蟲,真是陰魂不散,被搞得精疲力盡啊。好在之前寫的代碼還算比較規(guī)范,層次分明,明顯的問題通過屏蔽不同的功能段來快速定位問題點(diǎn),所以再寫代碼時(shí)就應(yīng)該想到層次段落分明,這樣在后面遇到問題時(shí)也好更快的查找,不至于牽一發(fā)而動(dòng)全身??傊畧?jiān)持原則“高內(nèi)聚,低耦合”,剛學(xué)習(xí)編程時(shí)這個(gè)原則會(huì)灌輸給你,但是不經(jīng)歷大的工程項(xiàng)目是很難體會(huì)其意。然而總會(huì)存在一些難以查找的問題,不過今天從老大那里學(xué)習(xí)了一招很非常優(yōu)雅的調(diào)試方式,即使這種方式?jīng)]有找到問題的最終原因,但是也排除了某些可能引起問題的原因。我使用此方法是在STM32的在線Debug中使用,在其他調(diào)試方式下未做測試,在此只是提供一種方法而已,分享一下。
再嵌入式開發(fā)中動(dòng)態(tài)內(nèi)存是比較常用,特別是對那些數(shù)據(jù)長度只有在運(yùn)行過程中才能確定的數(shù)據(jù),這個(gè)時(shí)候malloc()函數(shù)和free()函數(shù)就大大的派上了用場,千萬要記住,這兩個(gè)函數(shù)在非特殊情況下一定要成對出現(xiàn),不然很可能會(huì)出現(xiàn)錯(cuò)誤。此方法的目的是記錄那些調(diào)用malloc的函數(shù)在使用malloc時(shí)分配了多少內(nèi)存,可以一目了然的清楚哪個(gè)函數(shù)分配了多少內(nèi)存。知道了哪函數(shù)調(diào)用了malloc()函數(shù)且該函數(shù)申請了多少內(nèi)存。這樣就可以確定是哪個(gè)函數(shù)在干壞事了。具體實(shí)現(xiàn)如下:
#define ts_malloc(size) __ts_malloc(size, __FUNCTION__)
#define ts_free(p) __ts_free(p)
#pragma pack(push,1) // <! 字節(jié)對齊
struct mem_leak_t{
struct mem_leak_t *next;
char func_name[16];
uint32_t size;
};
#pragma pack(pop)
struct mem_leak_t *mem_leak_queue = NULL;
void *ts_malloc(size_t size, char *func_name){ // <! 實(shí)現(xiàn)此方法需要重新封裝malloc函數(shù)
uint32_t len = size + sizeof(struct mem_leak_t);
struct mem_leak_t *p = (struct mem_leak_t *)malloc(len);
if( p != NULL){
strncpy(p->func_name, func_name, sizeof(p->func_name) );
p->size = size;
mount(&mem_leak_queue, p);
return (p+1);
}else{return NULL;}
}
void ts_free(void *__p){
if( __p == NULL){return;}
struct mem_leak_t *p = (struct mem_leak_t *)__p;
p -= 1;
unmount(&mem_leak_queue, p);
free(p);
}