Vra

In .NET perspektief:

  • Wat is 'n geheue lek?
  • Hoe kan jy bepaal of jou aansoek lek?Wat is die gevolge?
  • Hoe kan jy 'n geheuelek voorkom?
  • As jou toepassing geheuelek het, gaan dit weg wanneer die proses afloop of word doodgemaak?Of beïnvloed geheuelekkasies in jou toepassing ander prosesse op die stelsel selfs nadat die proses voltooi is?
  • En wat van onbestuurde kode wat verkry word via COM Interop en/of P/Invoke?
Was dit nuttig?

Oplossing

Die beste verduideliking wat ek gesien het, is in hoofstuk 7 van die gratis Grondslae van programmering e-boek.

Basies, in .NET 'n geheuelek vind plaas wanneer verwysde voorwerpe gewortel is en dus nie vullis versamel kan word nie.Dit gebeur per ongeluk wanneer jy vashou aan verwysings buite die beoogde omvang.

Jy sal weet dat jy lekkasies het wanneer jy OutOfMemoryExceptions begin kry of jou geheuegebruik gaan groter as wat jy sou verwag (PerfMon het goeie geheue tellers).

Begrip .NETse geheuemodel is jou beste manier om dit te vermy.Spesifiek, om te verstaan ​​hoe die vullisverwyderaar werk en hoe verwysings werk - weereens, ek verwys jou na hoofstuk 7 van die e-boek.Wees ook bedag op algemene slaggate, waarskynlik die mees algemene gebeurtenisse.Indien voorwerp A is geregistreer vir 'n gebeurtenis op voorwerp B, maak dan beswaar A sal vashou totdat voorwerp B verdwyn omdat B het 'n verwysing na A.Die oplossing is om jou gebeurtenisse te deregistreer wanneer jy klaar is.

Natuurlik sal 'n goeie geheueprofiel jou toelaat om jou voorwerpgrafieke te sien en die nes/verwysing van jou voorwerpe te verken om te sien waar verwysings vandaan kom en watter wortelvoorwerp verantwoordelik is (rooi-hek miere profiel, JetBrains dotMemory, memprofiel is regtig goeie keuses, of jy kan slegs die teks gebruik WinDbg en SOS, maar ek sal 'n kommersiële/visuele produk sterk aanbeveel, tensy jy 'n regte ghoeroe is).

Ek glo onbestuurde kode is onderhewig aan sy tipiese geheuelekkasies, behalwe dat gedeelde verwysings deur die vullisverwyderaar bestuur word.Ek kan verkeerd wees oor hierdie laaste punt.

Ander wenke

Streng gesproke verbruik 'n geheuelek geheue wat "nie meer gebruik word nie" deur die program.

"Nie meer gebruik nie" het meer as een betekenis, dit kan beteken "nie meer verwysing daarna nie", dit wil sê, totaal onherstelbaar, of dit kan beteken, verwys, herwinbaar, ongebruik, maar die program behou die verwysings in elk geval.Slegs die latere geld vir .Net vir perfek bestuurde voorwerpe.Nie alle klasse is egter perfek nie en op 'n sekere punt kan 'n onderliggende onbestuurde implementering hulpbronne permanent uitlek vir daardie proses.

In alle gevalle verbruik die toepassing meer geheue as wat streng nodig is.Die newe-effekte, afhangende van die hoeveelheid wat uitgelek is, kan gaan van geen, tot verlangsaming wat veroorsaak word deur oormatige versameling, tot 'n reeks geheue-uitsonderings en uiteindelik 'n noodlottige fout gevolg deur gedwonge prosesbeëindiging.

Jy weet 'n toepassing het 'n geheueprobleem wanneer monitering toon dat meer en meer geheue aan jou proses toegewys word na elke vullisversamelingsiklus.In so 'n geval hou jy óf te veel in die geheue, óf 'n onderliggende onbestuurde implementering lek.

Vir die meeste lekkasies word hulpbronne herwin wanneer die proses beëindig word, maar sommige hulpbronne word nie altyd in sommige presiese gevalle herwin nie, GDI-wyserhandvatsels is berug daarvoor.Natuurlik, as jy 'n interproses-kommunikasiemeganisme het, sal geheue wat in die ander proses toegewys is nie vrygestel word totdat daardie proses dit bevry of beëindig word nie.

Ek dink die "wat is 'n geheue lek" en "wat is die gevolge" vrae is al goed beantwoord, maar ek wou nog 'n paar dinge by die ander vrae byvoeg ...

Hoe om te verstaan ​​of jou aansoek lek

Een interessante manier is om oop te maak perfmon en voeg spore vir # grepe in alle hope en # Gen 2 versamelings , kyk in elke geval net na jou proses.As die uitoefening van 'n spesifieke kenmerk veroorsaak dat die totale grepe toeneem, en daardie geheue bly toegewys na die volgende Gen 2-versameling, kan jy sê dat die kenmerk geheue lek.

Hoe om te voorkom

Ander goeie menings is gegee.Ek wil net byvoeg dat miskien die mees algemeen oor die hoof gesien oorsaak van .NET geheue lekkasies is om gebeurtenishanteerders by voorwerpe te voeg sonder om dit te verwyder.'n Gebeurtenishanteerder wat aan 'n objek gekoppel is, is 'n vorm van verwysing na daardie objek, dus sal versameling voorkom selfs nadat alle ander verwysings weg is.Onthou altyd om gebeurtenishanteerders los te maak (met die -= sintaksis in C#).

Gaan die lek weg wanneer die proses afloop, en wat van COM-interop?

Wanneer u proses afsluit, word alle geheue wat in sy adresruimte gekarteer is, deur die bedryfstelsel herwin, insluitend enige COM-voorwerpe wat vanaf DLL's bedien word.Betreklik selde kan COM-voorwerpe vanaf afsonderlike prosesse bedien word.In hierdie geval, wanneer jou proses afloop, kan jy steeds verantwoordelik wees vir geheue wat in enige COM-bedienerprosesse wat jy gebruik het, toegewys is.

Ek sou geheuelekkasies definieer as 'n voorwerp wat nie al die geheue wat toegeken is, vrymaak nadat dit voltooi is nie.Ek het gevind dat dit in jou toepassing kan gebeur as jy Windows API en COM gebruik (d.w.s.onbestuurde kode wat 'n fout in het of nie korrek bestuur word nie), in die raamwerk en in derdeparty-komponente.Ek het ook gevind dat dit die probleem kan veroorsaak om nie op te ruim nadat jy sekere voorwerpe soos penne gebruik het nie.

Ek persoonlik het Geheue-uitsonderings gehad wat veroorsaak kan word, maar nie eksklusief is vir geheuelekkasies in dotnet-toepassings nie.(OOM kan ook kom van vaspen sien Speld Artical vas).As jy nie OOM-foute kry nie of moet bevestig of dit 'n geheuelek is wat dit veroorsaak, dan is die enigste manier om jou aansoek te profileer.

Ek sal ook die volgende probeer verseker:

a) Alles wat Idisposable implementeer, word weggedoen met óf 'n finale blok óf die gebruiksverklaring, dit sluit in borsels, penne ens. (sommige mense argumenteer om alles bykomend tot niks te stel)

b) Enigiets wat 'n sluitingsmetode het, word weer gesluit deur gebruik te maak van finaal of die gebruik-stelling (alhoewel ek gevind het dat gebruik nie altyd sluit nie, afhangende of jy die voorwerp buite die gebruik-stelling verklaar het)

c) As jy onbestuurde kode/Windows API's gebruik, word dit korrek hanteer.(sommige het skoonmaakmetodes om hulpbronne vry te stel)

Hoop dit help.

As jy 'n geheuelek in .NET moet diagnoseer, kyk na hierdie skakels:

http://msdn.microsoft.com/en-us/magazine/cc163833.aspx

http://msdn.microsoft.com/en-us/magazine/cc164138.aspx

Daardie artikels beskryf hoe om 'n geheuestorting van jou proses te skep en hoe om dit te ontleed sodat jy eers kan bepaal of jou lekkasie nie bestuur of bestuur word nie, en as dit bestuur word, hoe om uit te vind waar dit vandaan kom.

Microsoft het ook 'n nuwer instrument om te help met die generering van ongelukstortings, om ADPlus te vervang, genaamd DebugDiag.

http://www.microsoft.com/downloads/details.aspx?FamilyID=28bd5941-c458-46f1-b24d-f60151d875a3&displaylang=en

Gebruik CLR Profiler van Microsoft http://www.microsoft.com/downloads/details.aspx?familyid=86ce6052-d7f4-4aeb-9b7a-94635beebdda&displaylang=en is 'n goeie manier om te bepaal watter voorwerpe geheue hou, watter uitvoeringsvloei tot die skepping van hierdie voorwerpe lei, en ook om te monitor watter voorwerpe waar op die hoop woon (fragmentasie, LOH, ens.).

Die beste verduideliking van hoe die vullisverwyderaar werk, is in Jeff Richters CLR via C# boek, (hfst.20).Die lees hiervan gee 'n goeie grondslag om te verstaan ​​hoe voorwerpe voortduur.

Een van die mees algemene oorsake om voorwerpe per ongeluk te wortel, is deur gebeurtenisse buite 'n klas aan te sluit.As jy 'n eksterne gebeurtenis aansluit

bv.

SomeExternalClass.Changed += new EventHandler(HandleIt);

en vergeet om dit af te haak wanneer jy weggooi, dan het SomeExternalClass 'n ref vir jou klas.

Soos hierbo genoem, is die SciTech geheue profiler is uitstekend om vir jou wortels te wys van voorwerpe wat jy vermoed lek.

Maar daar is ook 'n baie vinnige manier om na te gaan dat 'n spesifieke tipe net WnDBG gebruik (jy kan dit selfs in die VS.NET onmiddellike venster gebruik terwyl dit aangeheg is):

.loadby sos mscorwks
!dumpheap -stat -type <TypeName>

Doen nou iets wat jy dink die voorwerpe van daardie tipe sal wegdoen (bv.maak 'n venster toe).Dit is handig hier om iewers 'n ontfoutingsknoppie te hê wat sal loop System.GC.Collect() n paar keer.

Hardloop dan !dumpheap -stat -type <TypeName> weer.As die getal nie gedaal het nie, of nie soveel gedaal het as wat jy verwag het nie, dan het jy 'n basis vir verdere ondersoek.(Ek het hierdie wenk gekry van 'n seminaar wat gegee is deur Ingo Rammer).

Ek dink in 'n bestuurde omgewing sal 'n lek wees dat jy 'n onnodige verwysing na 'n groot stuk geheue rondhou.

Hoekom dink mense dat 'n geheuelek in .NET nie dieselfde is as enige ander lek nie?

'n Geheuelek is wanneer jy aan 'n hulpbron heg en dit nie laat gaan nie.U kan dit beide in bestuurde en in onbestuurde kodering doen.

Met betrekking tot .NET, en ander programmeringsinstrumente, was daar idees oor vullisversameling, en ander maniere om situasies te verminder wat jou toepassing sal laat lek.Maar die beste metode om geheuelekkasies te voorkom, is dat jy jou onderliggende geheuemodel moet verstaan, en hoe dinge werk, op die platform wat jy gebruik.

Om te glo dat GC en ander towerkuns jou gemors sal opruim, is die kort pad na geheuelekkasies, en dit sal moeilik wees om later te vind.

Wanneer jy onbestuurde kodering maak, maak jy gewoonlik seker om skoon te maak, jy weet dat die hulpbronne wat jy aangryp jou verantwoordelikheid sal wees om skoon te maak, nie die oppas s'n nie.

In .NET aan die ander kant dink baie mense dat die GC alles sal skoonmaak.Wel, dit doen iets vir jou, maar jy moet seker maak dat dit so is..NET omvou baie dinge, so jy weet nie altyd of jy met 'n bestuurde of onbestuurde hulpbron te doen het nie, en jy moet seker maak waarmee jy te doen het.Die hantering van lettertipes, GDI-hulpbronne, aktiewe gids, databasisse, ens. is tipies dinge waarna u moet kyk.

In beheerde terme sal ek my nek op om te sê dit gaan net een keer die proses is afgehandel/afgehandel.

Ek sien egter baie mense het dit, en ek hoop regtig dat dit sal eindig.Jy kan nie die gebruiker vra om jou toepassing te beëindig om jou gemors skoon te maak nie!Kyk na 'n blaaier, wat IE, FF ens kan wees, maak dan oop, sê, Google Reader, laat dit vir 'n paar dae bly, en kyk wat gebeur.

As jy dan 'n ander oortjie in die blaaier oopmaak, na een of ander webwerf blaai, dan die oortjie toemaak wat die ander bladsy gehuisves het wat die blaaier laat lek het, dink jy die blaaier sal die geheue vrystel?Nie so met IE nie.Op my rekenaar sal IE maklik 1 GiB geheue in 'n kort tydjie (sowat 3-4 dae) eet as ek Google Reader gebruik.Sommige nuusblaaie is selfs erger.

Ek dink in 'n bestuurde omgewing, 'n leak sou jy hou 'n onnodige verwysing na 'n groot stuk Herinnering rond.

Absoluut.Ook, nie die gebruik van die .Dispose() metode op weggooibare voorwerpe wanneer toepaslik kan mem-lekkasies veroorsaak.Die maklikste manier om dit te doen is met 'n gebruiksblok omdat dit outomaties .Dispose() aan die einde uitvoer:

StreamReader sr;
using(sr = new StreamReader("somefile.txt"))
{
    //do some stuff
}

En as jy 'n klas skep wat onbestuurde voorwerpe gebruik, as jy nie IDisposable korrek implementeer nie, kan jy geheuelekkasies vir jou klas se gebruikers veroorsaak.

Alle geheuelekkasies word opgelos deur programbeëindiging.

Lek genoeg geheue en die bedryfstelsel kan besluit om die probleem namens jou op te los.

Ek sal met Bernard saamstem oor in .net wat 'n memlek sou wees.

Jy kan jou toepassing profileer om die geheuegebruik daarvan te sien, en vas te stel dat as dit baie geheue bestuur wanneer dit nie moet wees nie, jy kan sê dat dit 'n lek het.

In bestuurde terme sal ek my nek op die spel plaas om te sê dit gaan weg sodra die proses doodgemaak/verwyder is.

Onbestuurde kode is sy eie dier en as 'n lekkasie daarin bestaan, sal dit 'n standaard mem.lek definisie.

Hou ook in gedagte dat .NET twee hope het, waarvan een die groot voorwerphoop is.Ek glo voorwerpe van ongeveer 85k of groter word op hierdie hoop geplaas.Hierdie hoop het 'n ander leeftydreëls as die gewone hoop.

As jy groot geheue strukture (Woordeboeke of Lys s'e) skep, sal dit verstandig wees om te gaan soek wat die presiese reëls is.

Wat betref die herwinning van die geheue by prosesbeëindiging, tensy u Win98 of dit gelykstaande is, word alles terug na die bedryfstelsel vrygestel by beëindiging.Die enigste uitsonderings is dinge wat kruis-proses oopgemaak word en 'n ander proses het steeds die hulpbron oop.

COM-voorwerpe kan tog moeilik wees.As jy altyd die IDispose patroon, jy sal veilig wees.Maar ek het 'n paar interop-samestellings teëgekom wat implementeer IDispose.Die sleutel hier is om te bel Marshal.ReleaseCOMObject wanneer jy daarmee klaar is.Die COM-voorwerpe gebruik steeds standaard COM-verwysingtelling.

ek het gevind .Net Memory Profiler 'n baie goeie hulp wanneer u geheuelekkasies in .Net vind.Dit is nie gratis soos die Microsoft CLR Profiler nie, maar is na my mening vinniger en meer tot die punt.A

Een definisie is: Kan nie onbereikbare geheue vrystel nie, wat nie meer aan nuwe proses toegewys kan word tydens die uitvoering van die toekenningsproses nie.Dit kan meestal genees word deur GC-tegnieke te gebruik of deur outomatiese gereedskap opgespoor te word.

Vir meer inligting, besoek gerus http://all-about-java-and-weblogic-server.blogspot.in/2014/01/what-is-memory-leak-in-java.html.

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top