代碼片段如下,linux,malloc200W和2W,耗時有約15倍的差距,請問是什么原因及如何優化啊?
char **cc;
cc = malloc(sizeof(char *)*2000000);
gettimeofday(&tv1, 0);
char ccc = 'a';
*(cc + 0) = 'a';
gettimeofday(&tv2, 0);
fprintf(stdout, "2.%lu,%lu,%lu,%lu\n", tv1.tv_sec, tv1.tv_usec, tv2.tv_sec, tv2.tv_usec);
uj5u.com熱心網友回復:
補充,耗時集中在賦值,不在malloc,malloc的差距可以忽略。uj5u.com熱心網友回復:
這里賦值不都一樣嗎?uj5u.com熱心網友回復:
賦值是一樣,關鍵是這個陣列大小不一樣,一個20W,一個2W,是否大小不一樣導致尋址程序不一樣呢uj5u.com熱心網友回復:
不會有差別的,你把測驗結果貼出來uj5u.com熱心網友回復:
不好意思,剛剛描述有點錯,是200W時對不同位置賦值,耗時不一樣,下面是代碼和結果char **cc;
cc = malloc(sizeof(char *)*2000000);
gettimeofday(&tv1, 0);
*(cc + 0) = 'a';
gettimeofday(&tv2, 0);
fprintf(stdout, "2.%lu,%lu,%lu,%lu\n", tv1.tv_sec, tv1.tv_usec, tv2.tv_sec, tv2.tv_usec);
gettimeofday(&tv1, 0);
*(cc + 1500000) = 'a';
gettimeofday(&tv2, 0);
fprintf(stdout, "2.%lu,%lu,%lu,%lu\n", tv1.tv_sec, tv1.tv_usec, tv2.tv_sec, tv2.tv_usec);
測驗結果
2.1589117027,554010,1589117027,554014
2.1589117027,554016,1589117027,554282
uj5u.com熱心網友回復:
你這個測驗不是很合理,*(cc+0)='a';編譯器沒有那么笨的,會優化的,所以你應該改一下位置不要用偏移為0,
其次你的變數為char型別,那么在偏移尋址,地址操作時就多了幾個尋址取數的匯編碼的尋址最快的是和總線相同位數的
再有一個你測驗分配記憶體測驗效率,應該盡量分配在一個物理記憶體頁中。
uj5u.com熱心網友回復:
謝謝gouyanfen的回復。1、改成偏移10,結果差不多,這個測驗是想知道對一個大陣列的不同位置,由其是距離起點不同距離的位置賦值是否耗時一致;
char **cc;
cc = malloc(sizeof(char *)*2000000);
gettimeofday(&tv1, 0);
*(cc + 10) = 'a';
gettimeofday(&tv2, 0);
fprintf(stdout, "2.1.%lu,%lu,%lu,%lu\n", tv1.tv_sec, tv1.tv_usec, tv2.tv_sec, tv2.tv_usec);
gettimeofday(&tv1, 0);
*(cc + 1500000) = 'a';
gettimeofday(&tv2, 0);
fprintf(stdout, "2.2.%lu,%lu,%lu,%lu\n", tv1.tv_sec, tv1.tv_usec, tv2.tv_sec, tv2.tv_usec);
測驗結果
2.1. 1589123428,159323,1589123428,159328
2.2. 1589123428,159329,1589123428,159613
2、變數是char型別是因為實際專案中這里是個自定義的結構,結構大小沒法保持和總線位數一樣;
3、雖然這個測驗的目的不是記憶體分配效率,不過,怎樣才能分配在一個物理記憶體頁呢,那樣的話賦值效率應該也會高些;
uj5u.com熱心網友回復:
我覺得你可以把cc轉為unsigned int 然后再運算+偏移,不要用他本身的型別
*(cc+150000)='a'
這個運算是 cc+sizeof(char)*150000
*(char*)((int)cc+150000)='a';
這樣看會不會快些
uj5u.com熱心網友回復:
我拿Linux來解釋,不完全準確,可以近似這樣理解。當你malloc了200W位元組的時候,系統實際上給你開了個空頭支票。你雖然拿到了分配的記憶體的地址,但底層的物理記憶體壓根就沒有分配,只是做了個備案。當你開始往記憶體中寫東西的時候,系統才開始給你分配真正的物理記憶體,而且容易想象,你寫的地址的offset越大,系統需要真正準備的物理記憶體越多,花的時間越長。
想要準確的解釋,可以去看虛擬記憶體這塊。
uj5u.com熱心網友回復:
修改成*(char*)((int*)cc+150000)='a';
后,運行2次,第一次有大幅改善,第二次結果跟之前差不多,結果如下
2.1. 1589128544,452039,1589128544,452045
2.2. 1589128544,452047,1589128544,453108
2.1. 1589128846,724661,1589128846,724667
2.2. 1589128846,724669,1589128846,724929
后來再多次運行,結果類似第二次。
猜測,第一次剛好如你上面所說,cc分配在同一物理頁了,所以快了很多,因為單從陣列來說,操作各個位置的復雜度應該是O(1),但是到尋址這一步,如果跨了分頁,那么離起點越遠就步驟越多,越耗時。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/67783.html
標籤:C語言
上一篇:cmd命令寫bat
下一篇:獲取wan口IP
