游戏乐悠悠网游开发网

 找回密码
 立即注册
查看: 1274|回复: 0
打印 上一主题 下一主题

window 下 Unreal3 的内存管理(三)

[复制链接]
  • TA的每日心情
    无聊
    2014-8-8 12:31
  • 签到天数: 37 天

    [LV.5]常住居民I

    鲜花(0) 鸡蛋(0)
    跳转到指定楼层
    楼主
    发表于 2012-2-26 09:17:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    为了每次很块的能找到对应的PoolTable,接下来初始化这个' y" c6 C/ I, u- x
    . K. g% L% j  d: o/ q$ \
    for( DWORD i=0; i<OOL_MAX; i++ )$ M" D- U1 n0 V% m7 \) G2 J
      {
       DWORD Index;
       for( Index=0; PoolTable[Index].BlockSize<i; Index++ );$ d$ {' H) h& o/ R' }. o
       checkSlow(Index<OOL_COUNT);; k* F+ z! n5 J( I1 y0 G$ y" j
       MemSizeToPoolTable = &oolTable[Index];
      }

    也就是说我分配0 到POOL_MAX之间的大小可以直接做为MemSizeToPoolTable的索引,找到对应的PoolTable。至于要用多少的PoolTable这个其实无所谓了,u3 里面为42个。

    现在说下U3里面做的最有技巧的东西,大家知道WINDOW32bit下指针是32位,也就是说寻址虚拟内存对大地址是32位,每次分配最小空间是4KB,分配粒度是64KB(其实你在WINDOWS下调用new,分配大小都是4KB对齐的,也就是你分配不足4kb也会给你4kb,这样其实浪费了很多空间。)+ X( I& A. c& T2 S$ _

    为了快速申请和释放内存,它把这32位前16位作为索引,作为FPoolInfo数组的索引,这样可以很快找到这个FPoolInfo。因为Windows32分配都是4kb对齐的,我申请空间是2的16次方字节,也就是说我把32位的后16位都占满了,因为分配粒度保证了64KB,这样所有0x####0000 ----------0x####FFFF地址的都用我这个FPoolInfo来管理。如果直接创建FPoolInfo数组的话,因为前16位做索引,那么要创建2的16次方 × sizeof(FPoolInfo)大小空间,你想想你虚拟内存4GB,32地址能都用了吗?显然是不可能的,直接诶创建这么大空间很浪费的,所以U3做了2级索引,前5位一个级别,后11位一个级别,后面是11是动态创建的,后面选择大于7位其实就可以,因为2的7次方 ×sizeof(FPoolInfo)等于4KB,至于为什么选择11和5可能是经验值吧。. Z. @1 \: J" X; ]+ H4 }

    FPoolInfo* PoolIndirect[32]; //32 用来表示前5位一级索引,当访问一级索引为空的时候就会调用下面的函数创建出来,这样可以用2级别索引。
    1 w. D  V  B# V  J6 l
    FPoolInfo* CreateIndirect()* m+ {9 ?6 ^) e; h( z% U
    {
      FPoolInfo* Indirect = (FPoolInfo*)VirtualAlloc( NULL, 2048*sizeof(FPoolInfo), MEM_COMMIT, PAGE_READWRITE );
      if( !Indirect )
      {0 v2 E" N2 S& g0 d1 [8 t3 h8 ~) N- Q
       OutOfMemory();
      }
      return Indirect;# M. \' H0 h; b
    }3 {1 r& @" ~( ]
    , u" X0 T( d" |3 G
      y+ N+ ~# m" t) {% d' ~

    virtual void* Malloc( DWORD Size, DWORD Alignment )
    {
      check(Alignment == DEFAULT_ALIGNMENT && "Alignment currently unsupported in Windows");7 ]( D/ a' |: B* P  S
      MEM_TIME(MemTime -= appSeconds());
      STAT(CurrentAllocs++);
      STAT(TotalAllocs++);- I* {' p; ~; ]/ a" W/ ?
      FFreeMem* Free;
      if( Size<OOL_MAX )    //如果小于一定size就用PoolTable管理
      {
       //为了快速定位用那个table : L6 w" I' w3 W+ h! L1 G
    $ p5 [) F( M0 `7 E( C
       FPoolTable* Table = MemSizeToPoolTable[Size];
       checkSlow(Size<=Table->BlockSize);
       FPoolInfo* Pool = Table->FirstPool;
    ' K& I" i, U! c/ x

       if( !Pool )//查看当前是否有空闲的FPoolInfo,如果没有创建! D/ |& H; u" {, t1 ^" L
       {
        // Must create a new pool.
        DWORD Blocks  = 65536 / Table->BlockSize;    //看见了吧这里为什么用65536,也就是说Bytes   必然要小于65536 的,但要满                          //足4KB对齐 其实系统还是分配65536 大小。我给点建议,就是其实这里在开                          //始初始化每个TABLE时候,BlockSize最好可以被65536整除,Bytes  就等于                          //65536,保证不会有浪费的。
        DWORD Bytes   = Blocks * Table->BlockSize;3 ]0 _5 `* R: M+ u! B! y: }8 j2 S$ ]
        checkSlow(Blocks>=1);" g. Z1 X/ v3 q# r7 d8 t
        checkSlow(Blocks*Table->BlockSize<=Bytes);

        // Allocate memory.
        Free = (FFreeMem*)VirtualAlloc( NULL, Bytes, MEM_COMMIT, PAGE_READWRITE );
        if( !Free )' f: T3 u  O& n- K4 c" T" F
        {' F+ o! n2 W5 T" D1 D5 E
         OutOfMemory();$ I  v* ~% B3 T* Z, b
        }& y: Y$ [8 e# I& k5 @4 ?3 Z
    , A( L3 T$ C& Z0 i3 P
        // Create pool in the indirect table.
        FPoolInfo*& Indirect = PoolIndirect[((DWORD)Free>>27)];//先移动5位做一次索引
        if( !Indirect )//如果为空则创建
        {
         Indirect = CreateIndirect();
        }) c6 f! n, O- P3 D! n2 s) O6 E$ R
        Pool = &Indirect[((DWORD)Free>>16)&2047];//然后做2级别索引

        // Init pool. //初始化时这个pool,前面说了每次从系统申请的内存都会交给这个poolInfo来管理,而poolTable管理poolInfo,并且所有

    //poolInfo是最小分配内存块都是为BlockSize大小
        Pool->Link( Table->FirstPool );//因为当前Table没有空闲的pool所以,把这个pool链接到空闲列表,

       Pool->Mem            = (BYTE*)Free;; z4 X2 c2 C8 ~/ R2 L. x' e$ o
        Pool->Bytes       = Bytes;
        Pool->OsBytes   = Align(Bytes,PageSize);$ ]  b6 H& \* V* f8 C0 n3 a) ~! R% H
        STAT(OsPeak = Max(OsPeak,OsCurrent+=Pool->OsBytes));+ o5 q2 ?0 r! i6 v' Q
        Pool->Table       = Table;
        Pool->Taken    = 0;7 w6 S# |) @! @! ]! L
        Pool->FirstMem       = Free;

        // Create first free item.
        Free->Blocks         = Blocks;1 c1 |; N6 T/ [0 `
        Free->Next           = NULL;5 p7 H) z& y3 C  J* q7 w7 `4 i

    ( U. ]! L* D1 j( e; r

     pool会用申请的内存做一个memInfo的列表管理,就是  Pool->FirstMem ,这个列表里面记录所有空闲的小块,我不需要知道不是空闲的小块,毫无意义,可能有人问,那么这个链表记录应该有额外的数据结构把,其实不然,小块最小是8字节,正好是sizeof(memInfo)大小,我只记录没有分配出去,只要这块内存没有分配出去,我内部想怎么用就怎么用,随便记录memInfo信息。开始的时候创建的时候Bytes都可以用
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    小黑屋|手机版|Archiver|Online Game Xingbarking Dev Team  

    GMT+8, 2024-5-10 17:09 , Processed in 0.133824 second(s), 32 queries .

    Powered by Discuz! X3.2 Licensed

    © 2001-2013 Comsenz Inc.

    快速回复 返回顶部 返回列表