TMemoryStream的效能問題

2021-08-19 21:50:15 字數 2711 閱讀 1764

tmemorystream作為使用非常多的乙個stream類,日常使用時並沒有感覺到慢,這是因為**中使用頻度不高的緣故,當使用頻度一上去,tmemorystream的效能簡直不忍直視。好了,我們看看原始**是怎麼寫的:

function tmemorystream.realloc(var newcapacity: longint): pointer;

begin

if (newcapacity > 0) and (newcapacity <> fsize) then

newcapacity := (newcapacity + (memorydelta - 1)) and not (memorydelta - 1);

result := memory;

if newcapacity <> fcapacity then

begin

if newcapacity = 0 then

begin

globalfreeptr(memory);

freemem(memory);

result := nil;

end else

begin

if capacity = 0 then

result := globalallocptr(heapallocflags, newcapacity)

else

result := globalreallocptr(memory, newcapacity, heapallocflags);

if capacity = 0 then

getmem(result, newcapacity)

else

reallocmem(result, newcapacity);

if result = nil then raise estreamerror.createres(@smemorystreamerror);

end;

end;

end;

我們知道,tmemorystream最終操縱的是記憶體,那麼分配記憶體自然是對效能影響最大的部分,反映在**上就是下面紅色的兩行**:

if (newcapacity > 0) and (newcapacity <> fsize) then

newcapacity := (newcapacity + (memorydelta - 1)) and not (memorydelta - 1);

根據這兩行**,我們可以看出,每次最少分配8k記憶體,然後以8k的倍數進行增長。所以當向tmemorystream寫入n*8k資料時,理論上要分配n次記憶體,對於小於8k或者使用次數很少的memorystream來說完全不是問題。但是,一旦寫入資料很多,就非常非常麻煩了。

知道原因後,解決方案就很簡單了:

1。在寫入前直接分配足夠的記憶體來避免多次分配,使用tmemorystream.size = 你需要的記憶體數量(例如1024 *1024);來預先分配足夠的記憶體來使用。

2。使用自己的記憶體分配策略來分配記憶體。其實也很簡單,從tmemorystream繼承下來然後動態更改newcapacity的值即可。例如:當所需記憶體少於8k時還是直接分配8k,但大於8k且小於64m時一次增長原有記憶體的2倍(或者4倍或者8倍),大於64m且小於1g時一次增長0.5倍,超過1g時每次增長128m。這個記憶體分配策略只是舉例,可以根據自己的需要來進行調整。偽**大概像這樣:

if (newcapacity > 0) and (newcapacity <> fsize) then

begin

if fsize = 0 then

icapacity := newcapacity shl 1

else if fsize < c_64m then

icapacity := fsize shl 1

else if fsize < c_1g then

icapacity := fsize + fsize shr 1

else

icapacity := fsize + c_128m;

if icapacity < newcapacity then

icapacity := newcapacity shl 1;

if icapacity < fmemorydelta then

icapacity := fmemorydelta;

if icapacity > maxint then

icapacity := maxint;

newcapacity := icapacity;

newcapacity := (newcapacity + (fmemorydelta - 1)) and not (fmemorydelta - 1);

end;

這樣更改後,memorystream的效能可以有1~3個數量級的提公升,這時才能真正展現memorystream的威力。嗯,記憶體的快不是你想象中的快,而是超級快!

其實,memorystream的原始**畢竟寫於20年前,那時的pc機記憶體大概在8~16m左右,因此原有的記憶體分配**在當時是無可挑剔的,現在的情況完全不一樣了,畢竟動不動16g、64g的記憶體標配讓原有的記憶體分配**成為了瓶頸,這也是歷史原因和歷史遺留問題。還好,我們可以快速修正。

最後,順便說說tlist的問題,同樣,tlist也是20年前的**,在進行元素新增或者刪除時同樣存在記憶體分配和記憶體移動的問題。相信在簡單的更改後你也能輕鬆把效能提公升1~3個數量級!good luck!

CSS 的繼承性 層疊性 特殊性 重要性

1 繼承性 繼承是一種規則,它允許樣式不僅應用於某個特定html標籤元素,而且應用於其後代。如某種顏色應用於p標籤,這個顏色設定不僅應用p標籤,還應用於p標籤中的所有子元素文字,這裡子元素為span標籤。2 特殊性 標籤的權值為1,類選擇符的權值為10,id選擇符的權值最高為100。注意 還有乙個權...

事務的原子性,一致性,隔離性,永續性

事務的原子性 事務的原子性指的是,事務中包含的程式作為資料庫的邏輯工作單位,它所做的對資料改操作要全部執行,要麼全部不執行。這種特性稱為原子性。事務的原子性要求,如果把乙個事務看作是乙個程式,它要麼完整的被執行,要麼完全執行。就是說事務的操縱序列或者完全應用到資料庫或者完全不影響資料庫。這種特性稱為...

事務的原子性,一致性,隔離性,永續性

事務的原子性 事務的原子性指的是,事務中包含的程式作為資料庫的邏輯工作單位,它所做的對資料改操作要全部執行,要麼全部不執行。這種特性稱為原子性。事務的原子性要求,如果把乙個事務看作是乙個程式,它要麼完整的被執行,要麼完全執行。就是說事務的操縱序列或者完全應用到資料庫或者完全不影響資料庫。這種特性稱為...