function TMemoryManager.Allocate: PIOCPStruct; var i: Integer; begin FLock.Enter; try Result := nil; for i := 0 to FList.Count - 1 do begin Result := FList[i]; if not Result.Assigned then Break; end; if (not Assigned(Result)) or (Result.Assigned) then begin New(Result); FList.Add(Result); end; FillChar(Result^, SizeOf(TIOCPStruct), 0); Result.Assigned := True; Result.Active := False; finally FLock.Leave; end; end;这段代码的效率太低了。如果内存池中有几万个元素,在高并发的时候,需要命中的位置都在几千甚至几万的下标当中,那么这个选择Result.Assigned = false的for循环操作有多少是在浪费时间?基本上本意想提升效率,却在这里形成了瓶颈,这不就适得其反?
一种浮跃式(泡沫式)的池管理,仅供参考 with FMemoryList.LockList do try if Not lpBuffer^.Using then Exit;//非在用内存 lpBuffer^.Using := false;//闲置 //FLastUsing 指向最后一块被分配内存下标的指针,-1表示没有使用,在这里几乎是不可能出现的 if FLastUsing >= 0 then begin //将最后一块被分配的内存与当前须释放的内存交换位置(下标) //虽然每次释放都多了一个交换操作,由于在分配的时候,以及被交换的时候,都有更新自己所属的下标WhereXY //比起循环查询闲置内存,效率就要提升很多 lpTempBuffer := Items[FLastUsing]; if lpTempBuffer <> lpBuffer then begin //交换所属下标记录 lpTempBuffer^.WhereXY := lpBuffer^.WhereXY; lpBuffer^.WhereXY := FLastUsing; //交换位置 Items[FLastUsing] := lpBuffer; Items[lpTempBuffer^.WhereXY] := lpTempBuffer; end; Dec(FLastUsing); end; finally FMemoryList.UnlockList; self.Free;//每申请一个内存都对内存管理器增加一个引用计数,所以这里加以释放 end;
分配内存片断 with FMemoryList.LockList do try if (FLastMember <> FFirstMember) and (FLastUsing <> FLastMember) then begin //有闲置内存,取最前面一块闲置内存标示为占用 Inc(FLastUsing); lpBuffer := Items[FLastUsing]; Result := lpBuffer; end; if Result = nil then begin //没有闲置内存,则申请新内存 lpBuffer := CreateNewBuffer(LocalBytes); if lpBuffer = nil then Exit; //新内存增加到列表当中,并更新其“所属下标” lpBuffer^.WhereXY := Add(Pointer(lpBuffer)); Result := lpBuffer; Inc(FLastMember); FLastUsing := FLastMember; end; Result^.Using := true; Attach; //内存申请成功,则为内存管理器自身增加一个引用计数 finally FMemoryList.UnlockList; end;
=======================================
比如向系统申请了100M的内存作为内存池, 怎么一块一块分给客户端使用? 每次从内存池取的大小是固定大小还是按接收到客户端数据的大小来取出; 还有如果是按固定大小取出, 考虑系统的页大小不, 每页为4K; 如果按接收客户端数据大小来取内存池的空间, 我们怎么去维护这个内存池?
var
i: Integer;
begin
FLock.Enter;
try
Result := nil;
for i := 0 to FList.Count - 1 do
begin
Result := FList[i];
if not Result.Assigned then
Break;
end;
if (not Assigned(Result)) or (Result.Assigned) then
begin
New(Result);
FList.Add(Result);
end;
FillChar(Result^, SizeOf(TIOCPStruct), 0);
Result.Assigned := True;
Result.Active := False;
finally
FLock.Leave;
end;
end;这段代码的效率太低了。如果内存池中有几万个元素,在高并发的时候,需要命中的位置都在几千甚至几万的下标当中,那么这个选择Result.Assigned = false的for循环操作有多少是在浪费时间?基本上本意想提升效率,却在这里形成了瓶颈,这不就适得其反?
with FMemoryList.LockList do
try
if Not lpBuffer^.Using then Exit;//非在用内存 lpBuffer^.Using := false;//闲置 //FLastUsing 指向最后一块被分配内存下标的指针,-1表示没有使用,在这里几乎是不可能出现的
if FLastUsing >= 0 then
begin
//将最后一块被分配的内存与当前须释放的内存交换位置(下标)
//虽然每次释放都多了一个交换操作,由于在分配的时候,以及被交换的时候,都有更新自己所属的下标WhereXY
//比起循环查询闲置内存,效率就要提升很多
lpTempBuffer := Items[FLastUsing];
if lpTempBuffer <> lpBuffer then
begin
//交换所属下标记录
lpTempBuffer^.WhereXY := lpBuffer^.WhereXY;
lpBuffer^.WhereXY := FLastUsing;
//交换位置
Items[FLastUsing] := lpBuffer;
Items[lpTempBuffer^.WhereXY] := lpTempBuffer;
end;
Dec(FLastUsing); end;
finally
FMemoryList.UnlockList;
self.Free;//每申请一个内存都对内存管理器增加一个引用计数,所以这里加以释放
end;
try
if (FLastMember <> FFirstMember) and (FLastUsing <> FLastMember) then
begin
//有闲置内存,取最前面一块闲置内存标示为占用
Inc(FLastUsing);
lpBuffer := Items[FLastUsing];
Result := lpBuffer;
end;
if Result = nil then
begin
//没有闲置内存,则申请新内存
lpBuffer := CreateNewBuffer(LocalBytes);
if lpBuffer = nil then Exit;
//新内存增加到列表当中,并更新其“所属下标”
lpBuffer^.WhereXY := Add(Pointer(lpBuffer));
Result := lpBuffer;
Inc(FLastMember);
FLastUsing := FLastMember; end; Result^.Using := true;
Attach; //内存申请成功,则为内存管理器自身增加一个引用计数
finally
FMemoryList.UnlockList;
end;
不过看了几位的大佬的评论,还是挺有收获和共鸣的!
呵呵呵呵