龟速的malloc和神速的FastMM

原创 2011年12月02日 17:24:52

由于在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确实不失为一个顶级的内存管理器。

FastMM使用方法总结

配置步骤: 1、把BorlndMM.dll和FastMM_FullDebugMode.dll拷到应用程序可执行程序存放的目录。 2、在项目文件uses ShareMem和FastMMDebugSu...
  • chinajobs
  • chinajobs
  • 2015年07月04日 10:46
  • 650

FastMM内存管理器在使用多线程情况下需要注意的问题。

FastMM内存管理器在使用多线程情况下需要注意的问题。 问题1:   注:如果你在Delphi中,只是用TThread类创建线程,不会用到API函数CreateThread创建线程,哪么下面...
  • gencheng
  • gencheng
  • 2012年10月31日 10:57
  • 1919

FastMM 定位内存泄露的代码位置

FastMM 定位内存泄露的代码位置
  • shuaihj
  • shuaihj
  • 2011年03月17日 17:09
  • 8393

Delphi7 中使用FastMM

Delphi7 中使用FastMM 在工程的第一行引用FastMM4即可(注意,一定要在第一个Uses的位置),可以在调试程序时提示内存泄露情况,还可以生成报告。 在Delphi2007以后版本中,...
  • cai5
  • cai5
  • 2013年12月05日 15:51
  • 5352

FastMM配置文件详解

FastMM配置文件详解
  • shuaihj
  • shuaihj
  • 2011年03月17日 17:14
  • 6174

经典面试题之new和malloc的区别

new和malloc的区别是C/C++一道经典的面试题,我也遇到过几次,回答的都不是很好,今天特意整理了一下。 0.       属性 new/delete是C++关键字,需要编译器支持。mall...
  • nie19940803
  • nie19940803
  • 2017年07月29日 21:29
  • 2514

百度云管家下载大文件龟速问题解决

事情发生的背景是我用百度云管家下载一个大概50G的东西,日日夜夜不关机下了两 个星期才下了不到50%,于是被激怒,真是为了赚钱把握好好的网给限速了,特写下解决 办法,希望能帮到大家...
  • qq_18140033
  • qq_18140033
  • 2015年07月01日 15:27
  • 1329

malloc函数详解以及和new的区别

详细了解malloc函数和new的运用以及相互区别
  • happyxieqiang
  • happyxieqiang
  • 2016年03月01日 21:35
  • 2252

malloc/free和new/delete的区别

malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要...
  • chance_wang
  • chance_wang
  • 2007年05月14日 22:31
  • 15410

delphi的fastmm

论: 1、绝对不可低估开源的力量!我们能由开源学到更多 ... 2、Dexter 抛弃了 BorlandMM,娶了 FastMM,因为 FastMM 勤快(效率更高),会持家(没有而外 DLL 的累赘...
  • iiprogram
  • iiprogram
  • 2006年04月08日 00:01
  • 2967
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:龟速的malloc和神速的FastMM
举报原因:
原因补充:

(最多只允许输入30个字)