程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 龜速的malloc和神速的FastMM

龜速的malloc和神速的FastMM

編輯:Delphi

 

由於在Delphi項目中,要頻繁創建和釋放大量小對象,因此擔心有效率問題,於是打於GetMem.inc看看,發現FastMM對於小塊內存作了很多工作,它預置了一組不同大小的內存池,當要創建一塊內存時,FastMM找到大小最相近的內存池分配之,內存釋放後回收到池中。這樣的做法雖有小量內存浪費,但效率卻是大大提高。

 

我決定做一個測試,看看效率研究如何:

 

 

const 

  cSize: Integer = 100; 

  cNum: Integer = 10000; 

var 

  N, I: Integer; 

  P: array [0..9999] of Pointer; 

  Fre: Int64; 

  Count1, Count2: Int64; 

  Time: Double; 

begin 

  QueryPerformanceFrequency(Fre); 

  QueryPerformanceCounter(Count1); 

 

  for I := 0 to 1000 - 1 do 

  begin 

    for N := 0 to cNum - 1 do 

      GetMem(P[N], cSize); 

    for N := 0 to cNum - 1 do 

      FreeMem(P[N]); 

  end; 

 

  QueryPerformanceCounter(Count2); 

  Time := (Count2 - Count1) / Fre; 

  Writeln(Format('Delphi2007 Release: %f', [Time])); 

end. 

上面例子中,循環1000次,每次循環分別創建和釋放10000個100字節的內存塊,運行結果如下:

 

  Delphi2007 Release: 0.14

結果非常好,這下我可以盡情使用小對象來替換記錄的工作了。

我想起C++的Malloc,不知其效率如何,於是我又將Delphi的測試代碼轉換成C++,代碼如下:

 

 

LARGE_INTEGER fre; 

LARGE_INTEGER count1, count2; 

double time; 

QueryPerformanceFrequency(&fre); 

const int cSize = 100; 

const int cNum = 10000; 

void* p[cNum]; 

 

QueryPerformanceCounter(&count1); 

for (int i = 0; i < 1000; ++i) 

    for (int n = 0; n < cNum; ++n) 

        p[n] = malloc(cSize); 

    for (int n = 0; n < cNum; ++n) 

        free(p[n]); 

QueryPerformanceCounter(&count2); 

time = (count2.QuadPart - count1.QuadPart) / (double)fre.QuadPart; 

printf("VC2008 Release: %f\n", time); 

運行結果使我震驚,這真是龜速的malloc:

  VC2008 Release: 3.854

看來malloc並沒有對小內存作任何優化,所以在C++中要大量使用動態對象,是必須要小心的,否則很容易引起性能問題。找了一些替換的內存管理器,始終沒有辦法達到FastMM的水平,最快的也只是其一半的速度。

最後我用自己實現的一個受限的內存管理器測試,該管理器只能創建固定大小的內存塊,也是用池的方式緩存內存塊,代碼如下:

 

LARGE_INTEGER fre; 

LARGE_INTEGER count1, count2; 

double time; 

QueryPerformanceFrequency(&fre); 

 

const int cSize = 100; 

const int cNum = 10000; 

void* p[cNum]; 

FixedAlloc myAlloc(cSize); 

QueryPerformanceCounter(&count1); 

for (int i = 0; i < 1000; ++i) 

    for (int n = 0; n < cNum; ++n) 

    {    

        //p[n] = malloc(cSize); 

        p[n] = myAlloc.Alloc(); 

    } 

    for (int n = 0; n < cNum; ++n) 

    { 

        //free(p[n]); 

        myAlloc.Free(p[n]); 

    } 

QueryPerformanceCounter(&count2); 

time = (count2.QuadPart - count1.QuadPart) / (double)fre.QuadPart; 

printf("VC2008 Release: %f\n", time); 

這次的結果很讓我滿意:

  VC2008 Release: 0.0806

速度比FastMM快了近一倍,但這並不表示它比FastMM好,因為FastMM更加通用,且處理了很多其他的邏輯,如果FixedAlloc做得更完善一些,或許會和FastMM接近的。因此可見,對效率很敏感的程序,使用特有的內存管理器是必須的,否則讓龜速的malloc來處理,一切都是龜速。

進一步想,如果打開多線程判斷,FastMM的效率不知如何,於是又有下面的測試代碼:

 

IsMultiThread := True; 

QueryPerformanceCounter(Count1); 

 

for I := 0 to 1000 - 1 do 

begin 

  for N := 0 to cNum - 1 do 

    GetMem(P[N], cSize); 

  for N := 0 to cNum - 1 do 

    FreeMem(P[N]); 

end; 

 

QueryPerformanceCounter(Count2); 

Time := (Count2 - Count1) / Fre; 

Writeln(Format('Delphi2007 Release:%f', [Time])); 

僅僅是把IsMultiThread打開,效果非常明顯:

  Delphi2007 Release:0.41

足足比單線程模式慢了3倍,但是如果我自己來處理多線程的情況呢,結果又是如何呢:

 

IsMultiThread := False; 

InitializeCriticalSection(CS); 

 

QueryPerformanceCounter(Count1); 

 

for I := 0 to 1000 - 1 do 

begin 

  for N := 0 to cNum - 1 do 

  begin 

    EnterCriticalSection(CS); 

    GetMem(P[N], cSize); 

    LeaveCriticalSection(CS); 

  end; 

  for N := 0 to cNum - 1 do 

  begin 

    EnterCriticalSection(CS); 

    FreeMem(P[N]); 

    LeaveCriticalSection(CS); 

  end; 

end; 

 

QueryPerformanceCounter(Count2); 

Time := (Count2 - Count1) / Fre; 

Writeln(Format('Delphi2007 Release:%f', [Time])); 

DeleteCriticalSection(CS); 

結果很糟糕:

  Delphi2007 Release:0.71

FastMM並不像Delphi7那樣,用臨界區來實現多線程安全,因此效率要比那個方案更高一些,FastMM確實不失為一個頂級的內存管理器。

 

摘自 colin小屋

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved