Frá tímaritsþema til verkefnaframkvæmdar
Viðeigandi þjónustu- og tæknisíður fyrir greinina
Þegar Delphi-forrit í rekstri hæglega „stækka“, dettur af og til út með Access Violations eða verður skyndilega óstöðugt eftir nokkra daga keyrslu, er það oftast ekki ein villa heldur mynstur: minni er úthlutað en ekki hreinsað upp – eða það er losað of snemma og notað síðar. Einmitt hér er FastMM FullDebugMode ómetanlegt. Ekki sem varanlegt ástand, heldur sem markvisst greiningartól sem breytir „ein staðar í heapinu er eitthvað bilað“ í eftirsannan orsök.
Ókosturinn: FullDebugMode framleiðir mikið magn af úttaki, dregur úr frammistöðu og getur fljótt leitt til misskilnings. Leak-Report sýnir ekki sjálfkrafa hvar „villan“ er. Og Stacktrace er aðeins jafn góður og táknaupplausnin (MAP-skrá, debug-upplýsingar, inlining). Í þessum pistli fer ég yfir typíska jaðartilfellið, útskýri hreinan aðferð og gildrur – þannig að þú finnur ekki aðeins leaks heldur leiðréttir þau varanlega.
Hvenær er FastMM FullDebugMode raunverulega gagnlegt
FastMM er í nútíma Delphi-útgáfum oft þegar sjálfgefinn minnisstjóri eða er í mörgum verkefnum þegar innbættur. FullDebugMode er hins vegar sérstök stilling: hann merkir minnisblokkir með viðbótarprófmynstrum, safnar úthlutunar-stacktraces og athugar afkastameiri fyrir heap-korruption (þ.e. skemmd stjórnunarupplýsing í heapinu, t.d. vegna buffer-overruns).
Ég nota FullDebugMode markvisst þegar eitt af eftirfarandi á við:
- Endurtekið Leak: Minnisnotkun eykst í prófunarkeyrslu fyrir hvern aðgerð (t.d. per beiðni, per innflutning, per UI-aðgerð).
- Sporadískar AVs: Sérstaklega þær sem koma „þarna svona og þarna“ í sama svæði (klassískt: Use-after-free).
- Heap-Korruption: Skilaboð eins og „Invalid pointer operation“, „Access violation in ntdll“ eða krasch við lokun/finalisieren.
- Leit að regression: Eftir refactoring, uppfærslu bókasafns eða skipti á þýðanda kemur skyndileg ný óstöðugleiki.
Það er ekki skynsamlegt að kveikja á FullDebugMode í öllum buildum. Overheadið er hátt, tímasetning (timing) breytist og race-conditions geta ýmist horfið eða færst í tíma. Fyrir langtímasrekstur hentar heldur létt eftirlit (t.d. Prozess-Working-Set, Private Bytes, teljarar per aðgerð) – FullDebugMode er skurðverkfærið, ekki púlsneminn.
Grunnregla: Leak-Report er einkenni, Stacktrace er vísbending
Leak-Report sýnir þér fyrst og fremst: að þessar blokkir eru enn úthlutaðar við lok forritsins. Þetta er aðeins sjálfkrafa vandamál ef þessar blokkir áttu í raun að hafa verið losaðar. Það eru lögmæt „leaks“: global singletons, cache, OS-handföng með ferlislíftíma eða third-party bókasöfn sem meðvitað finalisera ekki. Þessi tilvik viltu þekkja, en ekki laga þau blindandi.
Stacktrace-inn í reportinu sýnir staðinn þar sem blokk var úthlutað. Það er oft ekki sami staður þar sem þú gleymdir að kalla Free. Algeng raunsæi í eldri eða stækkuðum kerfum:
- Úthlutun í UI- eða service-lagi, en losun ætti að eiga sér stað í dýpri lagi (eignarhald óljóst).
- Úthlutun í Factory; eignarhald er fært til Caller – en Caller heldur að hann eigi hlutinn („owned“).
- Hlutur eru geymdir í Collections (listar, Dictionaries), en eignarhaldslíkanið er ekki samræmt.
- Path með excepcíu sleppir hreinsun þar sem try/finally vantar eða byrjar of seint.
Rétta ferlið er því: reproduzieren → isolieren → Stacktrace auflösen → Ownership-Fehler finden → Fix mit Regressionstest. FastMM liefert dir die Spuren, aber du musst sie in Architektur und Lebenszyklen übersetzen.
FastMM FullDebugMode sauber aktivieren (ohne Nebenwirkungen zu übersehen)
Í framkvæmd er FullDebugMode virkjaður með FastMM-valkostunum og viðeigandi FastMM-stillingu. Mikilvægara er ekki „wie genau heißt die Include-Datei“, heldur hvaða áhrif stillingin hefur og undir hvaða build-skilyrðum þú notar hana.
Mæltar forsendur fyrir Debug-Build
- Debug-DCUs und Debug-Infos: Stacktraces sind nur nützlich, wenn sie auf echte Unit/Zeile/Adresse auflösbar sind. Stelle sicher, dass Debug-Informationen erzeugt werden und eine MAP-Datei verfügbar ist.
- Optimierung bewusst wählen: Für Stacktrace-Lesbarkeit ist ein nicht-optimierter Build meist besser. Inlining und aggressive Optimierung können Stackframes „verwischen“.
- Gleiche Laufzeitbedingungen: Nutze möglichst gleiche Daten, gleiche Konfiguration, gleiche Rechte. Viele Leaks sind datenabhängig (z. B. seltene Formate, Sonderpfade).
- 64-bit vs. 32-bit trennen: Speicherverhalten, Alignment und Drittbibliotheken unterscheiden sich. Debugge in der Zielplattform, in der das Problem auftritt.
Eitt atriði sem Admins og tæknilegir leiðtogar vanmeta oft: FullDebugMode kann auch Timing verändern. Wenn du Threading im Spiel hast, können Race-Conditions dadurch anders auftreten. Deshalb ist es sinnvoll, parallel auch einen Lauf ohne FullDebugMode zu haben, der nur die Reproduktion bestätigt. FullDebugMode ist dann der Schritt zur Diagnose.
Vorsicht bei „ReportMemoryLeaksOnShutdown“
Delphi kann über ReportMemoryLeaksOnShutdown Leaks beim Programmende melden. Das ist praktisch, aber in komplexen Anwendungen (Services, Plug-in Host, lange Laufzeiten) kann es trügen: Beim Shutdown laufen Finalization-Abschnitte, Threads stoppen, Caches werden weggeräumt. Ein Leak, das in der Mitte der Laufzeit kritisch ist, kann bis zum Ende wieder verschwinden – oder umgekehrt: ein scheinbarer Leak entsteht erst im Shutdown, weil noch Hintergrundarbeit läuft.
Für praxistaugliches Leak-Hunting ist daher wichtiger: Leak pro Vorgang messen (z. B. nach 100 Requests), nicht nur beim Beenden. FastMM kann dabei helfen, aber der Testaufbau muss das abbilden.
Der typische Randfall: Leak-Report zeigt „irgendein Objekt“, aber die Ursache ist Ownership
Klassík í fyrirtækjaforritum: Innflutningsferli býr til hjálparhluti fyrir hverja færslu (t.d. StringLists, JSON-parse-objekt, tímabundnar listur). Á Happy Path er öllum hlutum hreinsað upp rétt. Í sjaldgæfum tilfellum (stökk vegna staðfestingar, exception, snöggt exit) situr hlutur eftir. Eftir 10.000 færslur verður það sýnilegt.
FastMM FullDebugMode hjálpar hér, því hann sýnir úthlutunarstaðinn. En „fíxið“ er ekki að kalla free á staðnum sem úthlutaði. Fíxið er traust Ownership-mynstur:
- Sá sem býr til hlutinn er ekki sjálfkrafa Owner.
- Ownership verður skýr í API-samningi (parametrar/retur, skjölun, nafngjafir).
- Söfn skulu vera ótvíræð: owning vs. non-owning. Blandaðar gerðir refsa sér.
- Exception-leiðir þurfa snöggar try/finally-blokkir.
Ef þú sérð úr stacktracen eingöngu „TStringList.Create“, þá er upplýsingin ekki gagnslaus – en hún segir þér aðeins: hér er eitthvað að verða til. Spurningin er: hvar á það að enda? Þar hjálpar arkitektúrhugsun meira en debugger-akróbatík.
Stacktraces korrekt lesen: Was du wirklich daraus ableiten kannst
Stacktrace úr FastMM er yfirleitt listi af return-adressum sem – með debug-táknum – kortleggjast á Units, aðferðir og helst línunúmer. Þegar þú lest hann skiptir þrennt mestu máli:
- Top-of-Stack ist nicht immer der Fehler: Efstu frame-in eru oft Memory-Manager/RTL. Það verður áhugavert þar sem þinn kóði byrjar.
- Call-Chain statt Einzelzeile: Línan er aðeins eitt atriði. Keðjan sýnir hvaða leið leiddi til úthlutunarinnar.
- Mehrere identische Blöcke: Ef FastMM skráir mörg leaks með sama stærð er það oft endurtekið stig. Það er gott: þá hefurðu endurtekningu.
Wenn Zeilennummern fehlen: MAP-Datei, Packages, Release-DCUs
Mörg teymi hrasa hér: FullDebugMode er virkur, leak-úttekt kemur, en í stað Unit/línu birtast aðeins adressur eða dularfull tákn. Algengar orsakir:
- Engin MAP-skrá eða debug-upplýsingar voru ekki framleiddar.
- Þú keyrir með Release-DCUs eða þriðja aðila DLL-um án tákna.
- Forritið notar Runtime Packages: hlutar kóðans eru í BPL-skrám og táknaleysið þarf að passa við þær.
- Hagræðing/inlining hefur gert stacktracið erfiðlesið.
Í framkvæmdinni þýðir þetta: Fyrir leak-veiðar þarftu build sem er meðvitað «diagnose-fær». Þetta er annað markmið en „mögulega hraðast“. Tæknilegir stjórnendur ættu að meðhöndla þetta sem sértækt build-prófíl, svo ekki hvert liðsstarfmaður breyti verkefnastillingum handvirkt.
Frames bewerten: „Interessant“ ist oft eine Zeile weiter oben
Dæmi úr raunveruleikanum (án tiltekins kóða viðskiptavinar): Stacktrace sýnir þér í fyrsta frame-ið í kóðanum rútínuna „LoadConfig“. Þú sérð þar hlutasköpun. Þú bætir við Free, Leak-ið hverfur – og allt í einu springur það annars staðar með Double Free. Af hverju? Vegna þess að „LoadConfig“ setur hlutinn í cache, og annar kóðabraut er þegar Owner og hreinsar síðar upp.
Rétta túlkunin hefði verið: Stacktrace sýnir þér, hvar blokkinn myndast. Við úrbætuna liggur oft í skilgreiningunni: Hver á hlutinn eftir Return? Ef þú svarar þessari spurningu ekki skýrt, breytir þú bara einkennum bilunarinnar (Leak → AV).
Heap-Korruption vs. Leak: Warum FullDebugMode oft den echten Übeltäter findet
Mörg „Leaks“ eru í raun afleiðingarvandamál: Buffer-Overrun ritar yfir Heap-Metadaten, Memory-Manager getur síðar ekki losað rétt, og í lokin sérðu tilviljunarkennd Leaks eða Invalid Pointer Operations. FullDebugMode er sterkur hér því hann notar prófunarmynstur og framkvæmir viðbótarstaðfestingar við Free/Reuse.
Mikilvægt er að greina á milli:
- Leak: Blokk var úthlutað og aldrei losað. Stöðugleiki versnar með tímanum; krahsi er ekki endilega óumflýjanlegur.
- Use-after-free: Blokk er losuð en er samt notuð síðar. Leiðir til sporadískra AVs sem erfitt er að endurgera.
- Double Free: Blokk er losuð tvisvar. Getur fallið samstundis eða ekki fyrr en síðar (þegar blokkinn hefur verið endurnýttur).
- Heap-Korruption: Einhver ritar yfir mörk blokkanna. Einkenni koma oft fram með tímafresti.
FullDebugMode er sérstaklega verðmætur þegar einkenni birtast með tímafresti. Viðbótarstaðfesting gerir villur sýnilegri fyrr – oft nákvæmlega þar sem rangur aðgangur á sér stað, ekki fyrst mínútum síðar í einhverju Free.
Aðferðafræði í verkefnum: Reproduzierbare Leak-Jagd statt „Debugging im Nebel“
Ef þú ætlar að eltast við minnisleka þarftu ferli sem er endurleikanlegt og auðvelt að deila í teymum. Ég vinn gjarnan með fastan greiningarramma:
1) Endurgerð í deterministischen Szenario
Settu upp prófsekvencu sem sýnir Leak-ið áreiðanlega: „Starte Service, verarbeite 500 Nachrichten, stoppe Service“ eða „Öffne Maske X, führe Aktion Y 200-mal aus“. Mikilvægt er að þú skjalfest sekvencuna með færibreytum (Datenbestand, Mandant, Feature-Flags), svo aðrir geti endurtekið hana.
2) Minimieren: Leak pro Schritt sichtbar machen
Ef sekvencan tekur 20 mínútur, skiptu henni. Markmiðið er að geta borið saman „vorher“ og „nachher“ eins fljótt og auðið er. Í stórum forritum er þetta oft sá tímatapi sem kostar mest, ekki sjálf lagfæringin.
3) FullDebugMode einschalten und Report interpretieren
Nú kemur FastMM FullDebugMode til sögunnar. Safnaðu skýrslunum, flokkaðu eftir blokkastærð/callstack og leitaðu að endurtekningum. Ein eftirliggjandi blokk getur verið lögmæt cache. 10.000 eins blokkir eru nánast alltaf raunverulegt leak.
4) Skýrleiki um eignarhald og viðgerð í viðeigandi lagi
Lagfærðu leka þar sem eignarhald er skilgreint: Factory, API-samningur, Collection-Wrapper. „Schnell ein Free einbauen“ beint við Create er oft rangur staður ef hluturinn er færður áfram.
5) Regression: sama röð, sami Build, sama Report
Lagfæringin er aðeins góð þegar röðin keyrir aftur og hvorki leaks né nýir minnisvillur koma upp. Sérstaklega við Use-after-free er „Leak weg“ ekki sönnun, heldur aðeins nýtt einkenni.
Algengar gildrur í Delphi-kóða sem FastMM gerir sýnilegar
Söfn og eignarhald (Listar, Dictionaries, Interfaces)
Mörg lekasöfn stafa ekki af flóknum reikniritum heldur af daglegum gagnauppbyggingum. Tveir klassískir villumynstrar:
- Listi inniheldur hluti, en enginn veit hver á að losa þá. Lausn: nota owning-Liste eða tæma kerfisbundið í finally.
- Dictionary heldur hlutum sem values; við Remove er value ekki losað eða það gleymist við Clear.
Auk þess eru Interfaces vandasöm: tilvísunartalning (svipuð ARC) er þægileg, en blandað notkun með objekt-eignarhaldi getur valdið leka vegna hringtengdra tilvísana eða events. FullDebugMode sýnir oft úthlutunarstíginn, en orsökin er tilvísunarhringur (A heldur B yfir Interface, B heldur A yfir Callback).
Exceptions og snemma útgöngur
Í eldri viðskiptaforritum eru exceptions oft hluti af eðlilegri stjórnun (t.d. staðfesting, aflýsing, retry). Vandamálið er sjaldan exception-ið sjálft heldur leiðin í kring: Hlutur er búinn til fyrir try/finally, svo kemur exception og hreinsun sleppist. FullDebugMode gefur þér stacktrace úthlutunarinnar – þú verður að athuga hvort til sé tryggður leið til losunar.
Threads og líftími: „Freigeben im falschen Thread“
Við VCL/FMX og þjónustur með worker-threads kemur upp annað jaðar-tilvik: Hlutur er búinn til í einum þræði en losaður í UI-þræði (eða öfugt), vegna þess að eitthvað er flutt „bara fljótt“ með Queue/Synchronize. Þetta getur virkað en getur líka leitt til Use-after-free ef framleiðandi heldur áfram á meðan neytandi er þegar að losa.
FastMM FullDebugMode getur hjálpað hér því hann greinir tímaseinkaðar villur fyrr. Raunveruleg leiðrétting er hins vegar hreint líftímalíkan: skýr eignarhald, afhending aðeins með óbreytanlegum (immutable) gögnum eða skýrir eigandaskiptapunktar.
Hvernig þú gerir skýrslur nothæfar: sía, bera saman, skjalfesta
Í teymum borgar sig að meðhöndla leak-reports ekki bara sem eitthvað til að „skoða“, heldur sem artefakt. Þrjár hagnýtar aðgerðir sem hafa reynst vel:
- Baseline-Report: ‘‘þekktur ástand‘‘ (t.d. núverandi útgáfa vörunnar) er keyrður einu sinni með FullDebugMode og vistaður sem viðmiðun. Þá sérðu nýja leka strax.
- Bera saman eftir notkunartilfelli: Fyrir viðkvæmar vinnuferðir (Import, Export, API-request, UI-massaaðgerð) setur þú upp stutta, reglulega endurtekna röð sem hægt er að keyra aftur og aftur.
- Skjalfest „lögmæt leaks“: Ef cache er meðvitað ekki finaliserað, skjalfestu það. Annars eltir einhver sömu færslurnar aftur eftir sex mánuði.
Þetta er ekki skriffinnska, heldur tímasparnaður: leit að leka fer annars fljótt í endalausa lykkju, því sömu mynstur koma upp á hverjum sprint.
Hvenær kostnaðurinn réttlætir sig – og hvenær þú ættir að fara aðra leið
FastMM FullDebugMode er greiningartól sem krefst auka vinnu. Það borgar sig sérstaklega þegar:
- Forritið keyrir lengi (þjónusta, Terminalserver‑viðskiptavinur, vaktakerfi, 24/7‑ferlar).
- Þú vinnur með raunverulega gagnastrauma frá viðskiptavinum og nærð ekki að prófa alla leiða í prófunum.
- Stöðugleiki skiptir meira máli en skammtímahraði í nýjum eiginleikum (eðlilegt í ferlisnæmum hugbúnaðarlausnum).
Ef þú ert hins vegar með lítið skrifborðsverkfæri sem lýkur eftir 30 sekúndur, er leit að leka oft undirorð. Sama á við ef um einstakt minnis‑spike vandamál er að ræða (t.d. stór útflutningur): þá er það oft ekki leka heldur spurning um streymisstefnu og hámarksálag í heap.
Praxisfazit: FullDebugMode ist kein Schalter, sondern ein Prozess
FastMM FullDebugMode kemur skipulagi á leit að minnisvillum: hann gerir úthlutanir sýnilegar, uppgötvar hrúgu‑spillingu fyrr og skilar stacktraces sem gera þér kleift að laga orsökina frekar en einkennið. Ákvarðandi áhrifinn er þó ekki tól sjálft, heldur ferlið: endurgeranlegar aðstæður, greiningarfærar builds, skýr reglur um eignarhald á minni og regression gagnvart grunnlínu.
Ef þú situr fastur í þrálátu leaki eða tilviljanakenndum heap‑villum og vilt varanlega auka stöðugleika í stærra Delphi‑kerfi, þá borgar sig að setja upp stutta, hreina greiningaruppsetningu með skýrri rás og úrvinnanlegum skýrslum. Ef þú þarft aðstoð við greiningu, build‑prófíla eða arkitektúr‑refaktoring: hafðu samband við Net-Base Software GmbH.
Fyrir þetta efni eru einnig Delphi Finna minnisleka og Fastmm Leak Report Lesa mikilvæg. Greinin setur þessa þætti í skiljanlegt samhengi og sýnir hvað skiptir máli í daglegri vinnu.
Næsta skref
Ef efnið verður að raunverulegu verkefni, ætti snemma að skoða kerfisarkitektúr, núverandi kerfi og rekstur í sameiningu.
Við styðjum ekki aðeins við einstakar spurningar, heldur einnig þegar úr kóðabútum, eldri kerfum eða gáttahugmyndum þarf að verða traust fyrirtækjaverkefni.
- Núverandi staða, markmynd og tæknileg áhætta eru metin saman.
- REST, aðgangur að gögnum, gáttir og innleiðing verða ekki flutt til síðari tíma sem afleiðingar.
- Þú sérð snemma hvaða leið er efnahagslega og rekstrarlega framkvæmanleg.