Managementul memoriei în Delphi 5.0: Manager de memorie
Articolul descrie modul în care programele utilizează memoria și listează principalele funcții ale managerului de memorie (nu trebuie confundate cu funcțiile de lucru cu memoria dinamică). Se pare că materialul are sens pentru majoritatea versiunilor ulterioare, dar dacă utilizați altceva decât Delphi 5.0, ar fi bine să vedeți lista de modificări.
În aplicația Delphi, managerul de memorie controlează toate alocările dinamice și libertățile de memorie. Procedurile standard New, Dispose, GetMem, ReallocMem și FreeMem funcționează prin aceasta, precum și alocarea de memorie pentru obiecte și linii lungi.
Managerul de memorie este dedicat aplicațiilor care alocă un număr mare de cantități mici de memorie, ceea ce este tipic pentru aplicațiile OOP și pentru aplicațiile care procesează datele de șir. Alți manageri de memorie (cum ar fi GlobalAlloc, LocalAlloc și heap support) nu sunt optime în aceste situații și pot încetini aplicația.
Pentru o performanță optimă, managerul de memorie funcționează direct cu API-ul Virtual Virtual Memory API (Win32 Virtual Memory API) prin intermediul funcțiilor VirtualAlloc și VirtualFree. Memoria este rezervată secțiunilor 1Mb și este alocată în blocuri de 16 Kb după cum este necesar.
Managerul de memorie controlează două variabile, AllocMemCount și AllocMemSize, care conțin numărul de blocuri alocate și suma totală a memoriei alocate. Aceste date ale aplicațiilor pot fi utilizate pentru depanare.
Modulul System conține două proceduri, GetMemoryManager și SetMemoryManager, care pot fi utilizate pentru interceptarea la nivel scăzut a apelurilor către managerul de memorie. Același modul reprezintă funcția GetHeapStatus, care returnează o înregistrare care conține informații detaliate despre starea administratorului de memorie.
Memoria pentru variabilele globale este alocată în segmentul de date al aplicației și este lansată când este finalizată. Variabilele locale trăiesc în stack. De fiecare dată când este apelată o procedură sau o funcție, memoria este alocată acestora, care este eliberată atunci când procedura sau funcția iese, deși optimizarea compilatorului le poate distruge mult mai devreme.
Stiva de aplicații este definită de două valori: dimensiunea minimă și maximă. Aceste valori sunt directive de compilare $ MINSTACKSIZE (implicit - 16 384 bytes) și $ MAXSTACKSIZE (implicit - 1.048.576 bytes). Winda va raporta o eroare dacă nu reușește să furnizeze dimensiunea minimă a memoriei pentru stack atunci când începe aplicația.
Dacă o aplicație necesită mai multă memorie decât cea specificată în $ MINSTACKSIZE, atunci este alocată în blocuri de 4 Kb. Dacă o altă alocare de memorie se rupe, sau pentru că memoria nu mai este, sau pentru că valoarea totală a teancului solicitate a depășit $ maxStackSize, este generat eksepshn: EstackOverflow, controlul preaplin Mai mult decât atât stiva este complet automat, directiva $ S, odată ce a împiedicat este dezactivat, este lăsat numai pentru compatibilitatea cu versiunile anterioare.
Variabilele dinamice create utilizând rutinele New sau GetMem sunt plasate pe heap și persistă până când sunt uciși prin Dispose și FreeMem respectiv.
Corzi lungi, șiruri largi, câmpuri dinamice, variante și interfețe sunt, de asemenea, plasate în heap, dar alocarea de memorie pentru ele este controlată automat de dispecer.
Descrierea variabilelor și funcțiilor
funcția AllocMem (Dimensiune: Cardinal): Pointer;
Selectează un bloc de memorie cu mărimea specificată în heap. Fiecare octet al memoriei alocate este setat la zero. Memoria liberă este utilizată pentru a elibera memoria.
var AllocMemCount: Integer;
Conține numărul de blocuri de memorie alocate. Această variabilă este incrementată de fiecare dată când utilizatorul solicită un nou bloc și scade atunci când blocul este eliberat. Valorile variabilelor sunt utilizate pentru a determina numărul de blocuri "rămase".
Deoarece variabila este globală și trăiește în modulul Sistem, utilizarea sa directă nu este întotdeauna sigură. Modulele care sunt legate în mod static vor avea diferite instanțe ale AllocMemCount. Legăturile statice sunt considerate aplicații care nu utilizează pachete runtime. Următorul tabel rezumă informațiile de utilizare pentru AllocMemCount, în funcție de tipul aplicației.
Aplicațiile care nu utilizează pachetele și dll-și Delphi se pot referi în siguranță la această variabilă globală, deoarece pentru ei există doar o copie a acesteia.
EXE cu pachete fără dll
Aplicațiile care utilizează pachete și nu utilizează dll-uri pot funcționa, de asemenea, cu AllocMemCount. În acest caz, toate modulele sunt legate dinamic și există doar o singură instanță a variabilei, deoarece pachetele, spre deosebire de DLL, sunt capabile să lucreze cu variabilele globale.
EXE cu dll-uri conectate static
Dacă aplicația și dll-urile acesteia sunt legate în mod static de biblioteca runtime (RTL), AllocMemCount nu ar trebui să fie utilizată direct, deoarece și aplicația, iar dll-ki va avea propriile instanțe. În schimb, ar trebui să utilizați funcția GetAllocMemCount, care trăiește în BorlandMM, care returnează valoarea variabilei globale AllocMemCount, declarată în BorlandMM. Acest modul este responsabil pentru alocarea memoriei pentru toate modulele, în lista de utilizări care este primul modul sharemem. Funcția în această situație este folosită deoarece variabilele globale declarate într-un DLL sunt invizibile pentru cealaltă.
EXE cu pachete și DLL-uri legate în mod static
Nu se recomandă crearea de aplicații mixte care utilizează ambele pachete și DLL-uri legate în mod static. În acest caz, ar trebui să lucrați cu atenție cu memorie alocată dinamic, deoarece fiecare modul va conține propriul cont AllocMemCount. referindu-se la memoria alocată și eliberată de acest modul.
var AllocMemSize: Integer;
Conține dimensiunea memoriei, în octeți, a tuturor blocurilor de memorie alocate de aplicație. De fapt, această variabilă arată câte octeți de memorie utilizează în prezent aplicația. Din moment ce variabila este globală, tot ceea ce este legat de AllocMemCount se aplică la ea.
GetHeapStatus
funcția GetHeapStatus: THeapStatus;
Returnează starea curentă a managerului de memorie.
tip
THeapStatus = înregistrare
TotalAddrSpace: Cardinal;
TotalUncitat: Cardinal;
Total comunicat: Cardinal;
TotalAlocat: Cardinal;
TotalFree: Cardinal;
FreeSmall: Cardinal;
FreeBig: Cardinal;
Nefolosit: Cardinal;
Overhead: cardinal;
Cod HeapError: Cardinal;
se încheie;
Dacă aplicația nu utilizează modulul ShareMem, atunci datele din intrarea TheStStatus sunt un heap global, altfel pot fi date despre o memorie partajată de mai multe procese.
Afișează câți octeți din TotalAddrSpace nu se află în fișierul swap.
Afișează câte octeți din TotalAddrSpace sunt în fișierul swap. În consecință, TotalCommited + TotalUncommited = TotalAddrSpace
Numărul de octeți de memorie totală alocați dinamic de programul dvs.
Memorie disponibilă, dar neutilizată (în octeți), situată în blocurile "mici".
Memorie disponibilă, dar neutilizată (în octeți) situată în blocuri "mari". Blocuri mari pot fi formate din secvențe continue de "mici".
Memorie (în bytes) niciodată alocată (dar accesibilă) de program. Nefolosit + FreeSmall + FreeBig = TotalFree.
Cât de multă memorie (în bytes) este necesară de managerul de heap pentru a gestiona toate blocurile alocate dinamic de programul tău.
Starea heapului intern
Rețineți că TotalAddrSpace, TotalUncommitted și TotalCommitted se referă la memoria sistemului de operare alocat pentru programul dvs., și TotalAllocated și TotalFree sunt memoria heap folosite pentru alocarea dinamică a memoriei de program. Astfel, pentru a monitoriza modul în care programul utilizează memorie dinamică, utilizați TotalAllocated și TotalFree.
Constantele pentru HeapErrorCode trăiesc în MEMORY.INC (recomandat pentru toți cei avansați și interesați). Pentru companie le vom aduce.
HeapErrorCode - valorile codurilor de eroare
procedura GetMemoryManager (var MemMgr: TMemoryManager);
Returnează un indicator la managerul de memorie curent. Structura TMemoryManager este descrisă mai jos.
TMemoryManager - structura de date
tip
PMemoryManager = ^ TMemoryManager;
TMemoryManager = înregistrare
GetMem: funcție (Dimensiune: Integer): Pointer;
FreeMem: funcție (P: Pointer): Integer;
Funcția ReallocMem: funcție (P: Pointer; Dimensiune: Integer): Pointer;
se încheie;
Această intrare determină ce funcții sunt utilizate pentru alocarea și eliberarea memoriei.
Funcția GetMem trebuie să aloce un bloc de memorie cu mărimea Dimensiune (Dimensiunea nu poate fi niciodată zero) și să returneze un indicator la ea. Dacă nu poate face asta, trebuie să se întoarcă la zero.
Funcția ReallocMem ar trebui să perevydelit Dimensiune memorie pentru blocul P. Aici, P nu poate fi zero, iar Dimensiunea nu poate fi 0 (deși ReallocMem apel nu de la managerul de memorie, este destul de acceptabil). Funcția trebuie să aloce memoria, dacă este necesar, să muteze blocul într-o locație nouă și să returneze pointerul în această locație. Dacă alocarea memoriei nu este posibilă, ar trebui să reveniți la zero.
var HeapAllocFlags: Cuvânt = 2;
Aceste steaguri sunt ghidate de managerul de memorie atunci când lucrează cu memoria. Ele pot fi combinate și pot lua următoarele valori (implicit - GMEM_MOVEABLE):
Alocă memorie fixă. pentru că Sistemul de operare nu poate muta blocuri de memorie și nu este necesar să blocheze memoria (respectiv nu poate fi combinată cu GMEM_MOVEABLE)
Alocă memorie mobilă. În Win32, blocurile nu pot fi mutate, dacă sunt localizate în memorie fizică, dar pot fi mutate în interiorul grămezii.
Când alocați memorie (de exemplu, funcția GetMem), toți octeții din această memorie vor fi setați la 0. (caracteristică excelentă)
Folosit pentru a schimba atributele unui bloc de memorie deja alocat
Prezentat pentru compatibilitate cu versiunile pe 16 biți, dar poate fi utilizat pentru a optimiza operațiile DDE. De fapt, cu excepția unor astfel de operațiuni, aceste steaguri nu ar trebui utilizate
Presetate, corespunde GMEM_FIXED + GMEM_ZEROINIT
Presetate, corespunde cu GMEM_MOVEABLE + GMEM_ZEROINIT
funcția IsMemoryManagerSet: Boolean;
Returnează TRUE dacă cineva a avut timp să-și piardă managerul implicit de memorie și să-și păstreze propriul loc.
procedura SetMemoryManager (const MemMgr: TMemoryManager);
Instalează un nou manager de memorie. Acesta va fi utilizat în alocarea și deallocation procedurile GetMem, FreeMem, ReallocMem, noi și aruncați, precum constructorii și destructorii de obiecte și de lucru cu siruri de caractere dinamice și matrice.
SysFreeMem, SysGetMem, SysReallocMem
Folosit când scrieți propriul manager de memorie. N-am găsit nici un alt sens în ele.
Cum se scrie managerul de memorie
Crezi că este foarte dificil? Nu contează ce este. Iată un exemplu din sistemul de ajutor propriu-zis: Delphi: acest dispecer va aminti numărul de alocări, eliberări și realocări ale memoriei:
var
GetMemCount: Integer;
FreeMemCount: Integer;
ReallocMemCount: Integer;
OldMemMgr: TMemoryManager;
funcția NewGetMem (Dimensiune: Integer): Pointer;
începe
Inc (GetMemCount);
Rezultat: = OldMemMgr.GetMem (Dimensiune);
se încheie;
funcția NewFreeMem (P: Pointer): Integer;
începe
Inc (FreeMemCount);
Rezultat: = OldMemMgr.FreeMem (P);
se încheie;
funcția NewReallocMem (P: Pointer; Dimensiune: Integer): Pointer;
începe
Inc (ReallocMemCount);
Rezultat: = OldMemMgr.ReallocMem (P, Dimensiune);
se încheie;
const
NewMemMgr: TMemoryManager = (
GetMem: NewGetMem;
FreeMem: NewFreeMem;
ReallocMem: NewReallocMem);
procedura SetNewMemMgr;
începe
GetMemoryManager (OldMemMgr);
SetMemoryManager (NewMemMgr);
se încheie;