2010-12-15 3 views
6

betrachten die Anwendung nächste ProbeWarum wird die Speicherauslastung meines Programms nach dem Freigeben von Speicher nicht wieder normal?

program TestMemory; 


{$APPTYPE CONSOLE} 

uses 
    PsAPI, 
    Windows, 
    SysUtils; 

function GetUsedMemoryFastMem: cardinal; 
var 
    st: TMemoryManagerState; 
    sb: TSmallBlockTypeState; 
begin 
    GetMemoryManagerState(st); 
    result := st.TotalAllocatedMediumBlockSize + st.TotalAllocatedLargeBlockSize; 
    for sb in st.SmallBlockTypeStates do 
    begin 
     result := result + sb.UseableBlockSize * sb.AllocatedBlockCount; 
    end; 
end; 

function GetUsedMemoryWindows: longint; 
var 
    ProcessMemoryCounters: TProcessMemoryCounters; 
begin 
    Result:=0; 
    ProcessMemoryCounters.cb := SizeOf(TProcessMemoryCounters); 
    if GetProcessMemoryInfo(GetCurrentProcess(), @ProcessMemoryCounters, ProcessMemoryCounters.cb) then 
    Result:= ProcessMemoryCounters.WorkingSetSize 
    else 
    RaiseLastOSError; 
end; 

procedure Test; 
const 
    Size = 1024*1024; 
var 
    P : Pointer; 
begin 
    GetMem(P,Size); 

     Writeln('Inside'); 
     Writeln('FastMem '+FormatFloat('#,', GetUsedMemoryFastMem)); 
     Writeln('Windows '+FormatFloat('#,', GetUsedMemoryWindows)); 
     Writeln(''); 

    FreeMem(P); 
end; 

begin 
     Writeln('Before'); 
     Writeln('FastMem '+FormatFloat('#,', GetUsedMemoryFastMem)); 
     Writeln('Windows '+FormatFloat('#,', GetUsedMemoryWindows)); 
     Writeln(''); 

     Test; 

     Writeln('After'); 
     Writeln('FastMem '+FormatFloat('#,', GetUsedMemoryFastMem)); 
     Writeln('Windows '+FormatFloat('#,', GetUsedMemoryWindows)); 
     Writeln(''); 
     Readln; 
end. 

die von der App zurückgegebenen Ergebnisse sind

Before 
FastMem 1.844 
Windows 3.633.152 

Inside 
FastMem 1.050.612 
Windows 3.637.248 

After 
FastMem 2.036 
Windows 3.633.152 

Ich möchte wissen, warum die Ergebnisse der Speichernutzung unterschiedlich sind in der Before und After:

+0

@Optimal Cynic - ist es wirklich schlau? Scheint, dass meine Anwendung nicht ungefähr 160 MB zurückgibt. Auf Computern mit 1 GB oder RAM (oder weniger) ist das keine Verschwendung von RAM? Details: http://stackoverflow.com/questions/4463979/my-program-never-releases-the-memory-back-why – Ampere

Antwort

11

Jeder Speichermanager (einschließlich FastMM) verursacht einen gewissen Overhead, sonst hätte Delphi nur die Windows-Speicherverwaltung verwenden können.

Der Unterschied, den Sie beobachten, ist der Overhead:

  • Strukturen, die FastMM zur Verfolgung von Speichernutzung zu halten,
  • Stücke des Speichers, der FastMM noch nicht in die Windows-Speicherverwaltung zurückkehrte ähnliche Speicher zu optimieren Zuweisungen in der Zukunft.
+0

Könnten Sie bitte kommentieren, "Inside - Windows" Wert – Branko

+0

@Branko bitte erläutern Sie Ihren Kommentar, da ich nicht verstehe, was Sie von mir erwarten. –

+0

@ JeroenWiertPluimers wahrscheinlich (nur raten) er spricht über die Rückgabe der TestMemory-Anwendung von OP. 'Inside ... Windows 3.637.248' – EMBarbosa

2

Weil der Speichermanager im Hintergrund clevere Dinge erledigt, um die Leistung zu beschleunigen.

+0

Zum Beispiel was? Wenn der Prozess die Arbeit großer Datenmengen aus dem Speicher freigibt, dann gibt es keinen Grund, Referenzen oder was auch immer beizubehalten, so würde ich sagen, dass idealerweise die Speichergröße die gleiche wie vor der Ausführung sein sollte. –

+1

Im Idealfall, wenn Sie Geschwindigkeit gegenüber Größe bevorzugen. –

+0

Und clever hängt auch vom Kontext ab. Ein extrem cleverer Speichermanager kann sowohl die Geschwindigkeit einer großen, komplexen Multithread-Anwendung beschleunigen als auch verringern - auf Kosten der Speicherverschwendung im Fall "Zuweisen, dann sofort freigeben". Ich weiß nicht genug über Delphis Speicherverwalter, um zu wissen, was genau es tut, aber ich weiß, dass Sie nicht von dem Beispiel in der Frage auf irgendeine Anwendung von vernünftiger Größe extrapolieren können. –

0

Wie funktioniert es getmem/malloc/free?

Heap Allocator - Wie von malloc verwendet ...

1) ordnet intern große Brocken (in der Regel bis zu 64 KB 1Megabyte) Arbeitsspeicher und dann Unter teilt die Stücke bis Sie die 100byte und 200byte Objekte zu geben und Zeichenfolgen im Programm. Wenn Sie Speicher freigeben, geschieht dies nur an der Stelle, an der sie im internen Puffer zugewiesen wurde, oder der Block wird dann als frei markiert. NICHTS TATSÄCHLICH!

2) Sie können sich also den HEAP als eine Liste großer Speicherbereiche vorstellen, und alle Objekte in Ihrem Programm sind nur kleine Teile dieser Blöcke.

3) Die großen internen Speicherbereiche werden nur freigegeben, wenn alle Objekte in ihnen freigegeben wurden. Der übliche Fall ist, dass beim Freigeben eines Objekts tatsächlich nichts passiert, bis einige Bits als verfügbar markiert werden.

Das ist eine ziemlich naive Beschreibung des Heap-Systems, aber die meisten Heaps funktionieren in ähnlicher Weise, aber viel mehr Optimierung als das. Aber Ihre Frage ist, warum geht die Erinnerung nicht unter und die Antwort ist, weil nichts wirklich befreit wird. Die internen Speicherseiten werden für den nächsten Aufruf von "neu" oder "malloc" etc ... beibehalten

PICTURE IT

INSIDE HEAP IST EINE RIESIGE BLOCK 100Kb

You call "malloc(1000)" or "getmem(1000)" to get a 1K block of memory. 

Dann werden alle Das ist der Fall, wenn der 1K-Speicherblock aus dem 100kb-Speicherblock entnommen wird und 99K Speicher in diesem Block verfügbar sind. Wenn Sie weiterhin malloc oder getmem aufrufen, wird der größere Block weiter unterteilt, bis ein weiterer größerer Block benötigt wird.

Jeder kleine Speicherblock, der einem Aufruf von malloc oder getmem zugewiesen wird, erhält tatsächlich 16 oder 24 zusätzliche Bytes (abhängig vom Zuordner) zusätzlichen Speicher. Dieser Speicher ist Bits, die der Zuordner verwendet, um zu wissen, was zugeordnet ist und wo es auch zugeordnet ist.

Verwandte Themen