游戏乐悠悠网游开发网

标题: window 下 Unreal3 的内存管理(三) [打印本页]

作者: tianyalanzi    时间: 2012-2-26 09:17
标题: window 下 Unreal3 的内存管理(三)
为了每次很块的能找到对应的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都可以用




欢迎光临 游戏乐悠悠网游开发网 (http://bbs.yxlyy.club/) Powered by Discuz! X3.2