Privacy Policy Cookie Policy Terms and Conditions Speicherleck - Wikipedia

Speicherleck

aus Wikipedia, der freien Enzyklopädie

Ein Speicherleck (englisch memory leak, gelegentlich auch Speicherloch oder kurz memleak) ist ein Ergebnis fehlerhafter Software. Ein solches Leck entsteht, wenn ein laufender Prozess einen Speicherbereich belegt, diesen jedoch im Zuge der Ausführung nicht mehr freigibt, durch einen Programmfehler aber selbst nicht mehr nutzen kann.

Inhaltsverzeichnis

[Bearbeiten] Problematik

In einem Computer steht nur in begrenztem Maße Arbeitsspeicher zur Verfügung. Hierbei handelt es sich um eine Ressource innerhalb des Systems, die das Betriebssystem den einzelnen Prozessen exklusiv zur Verfügung stellt. Das heißt, einmal zugeteilter Speicher kann einem Prozess nicht mehr durch das Betriebssystem entzogen oder von anderen Prozessen benutzt werden. Fordert ein Prozess kontinuierlich neuen Arbeitsspeicher an ohne andere Bereiche wieder freizugeben, so kommt es zu einem Ressourcenengpass der u. U. zum Abbruch des Prozesses oder gar zu einem Absturz des kompletten Systems führen kann.

Das Speichermanagment eines modernen Betriebssystems stellt mittels virtueller Speicherverwaltung einen Adressraum bereit, von dem ein Prozess einzelne Seiten zugeteilt bekommt. Sobald ein Prozess beendet ist, stehen die belegten Speicherbereiche wieder zur Verfügung und können von anderen Prozessen genutzt werden.

Ist das Betriebssystem nicht mehr in der Lage, Speicheranforderungen eines Prozesses zu erfüllen, schlägt die fragliche Reservierung fehl. Einige Betriebssysteme bieten die Möglichkeit, die Speicheransprüche eines einzelnen Prozesses bereits lange vor der Erschöpfung des freien Speichers nicht zu erfüllen, um so die Folgen fehlerhafter Programme im Vorfeld einzudämmen.

[Bearbeiten] Lösungsmöglichkeiten

Bei den möglichen Ansätzen zur Speicherverwaltung kann grundsätzlich zwischen zwei Alternativen unterschieden werden:

  1. Automatische Speicherbereinigung
  2. Explizite Speicherfreigabe

Es gibt folgende Ansätze zur Vermeidung von Speicherlecks:

  1. Analyse des Graphen aus Speicherbereichen (Knoten) und Referenzen (Kanten)
  2. Analyse des Quell-Codes ähnlich der formalen Verifikation
  3. Analyse konkreter Laufzeit-Situationen im Rahmen eines Software-Tests

Im folgenden sollen diese Alternativen kurz betrachtet werden.

[Bearbeiten] Automatische Speicherbereinigung

Falls die verwendete Laufzeitumgebung des Prozesses eine automatische Speicherbereinigung bereitstellt, kann der Anwendungsentwickler innerhalb des Programms Speicher adhoc belegen und verwenden. Sobald die Laufzeitumgebung feststellt, dass ein belegter Speicherbereich nicht mehr erreichbar ist, wird dieser wieder freigegeben. Nicht mehr erreichbar heißt in diesem Zusammenhang, dass keine gültige Variablenreferenz für den belegten Speicherbereich mehr existiert. Ein fehlerhafter Algorithmus kann jedoch auch dann noch ein Speicherleck produzieren, wenn wenigstens ein Speicherbereich referenziert werden kann, der aufgrund dieses Fehlers niemals wieder benutzt werden kann. Dieses Problem ist verwandt mit dem Halteproblem und wie dieses nur semi-entscheidbar.

Beispiele für Programmiersprachen mit einer Speicherverwaltung sind Java, Perl und Haskell.

[Bearbeiten] Explizite Speicherfreigabe

Im Gegensatz zur automatischen Speicherbereinigung kann der Anwendungsentwickler in anderen Programmiersprachen (C, C++ oder Pascal) die Speicherverwaltung selbst implementieren. Das heißt, es können dynamisch Speicherbereiche angefordert, verwendet und anschließend wieder freigegeben werden. Die Speicherbelegung erfolgt explizit und ist nicht an die Existenz einer Variablenreferenz gekoppelt.

Für die Anwendungsentwicklung bedeutet dies einen erheblichen zusätzlichen Aufwand und bildet eine häufige Fehlerquelle. Ein typischer Fehler ist zum Beispiel, dass Referenzen auf dynamisch belegten Speicher unbeabsichtigt überschrieben werden und der ursprünglich referenzierte Bereich nicht mehr freigegeben werden kann. Ein weiterer häufiger Fehler tritt auf, wenn relative Adressen innerhalb des Speicherbereichs falsch berechnet werden und über den vorgesehenen Speicherbereich hinaus geschrieben wird.

Die explizite Speicherfreigabe bietet dem Anwendungsentwickler jedoch mehr Möglichkeiten, die Verwendung der Ressource Hauptspeicher innerhalb der Anwendung selbst zu steuern. Dies ist insbesondere bei systemnahen Anwendungen, Echtzeitanwendungen oder mobilen Anwendungen von Bedeutung, da hier die nicht-funktionalen Anforderungen gegenüber dem Speicherbedarf bzw. dem Antwortzeitverhalten normaler Anwendungen abweichen.

[Bearbeiten] Systematische Tests

Durch systematisches Testen mit Hilfe entsprechender Werkzeuge, die mit einer gewissen Sicherheit feststellen können, welche Speicherbereiche einem Speicherleck zuzuordnen sind, kann man den Problemen der formalen Verifikation entgehen.

Ein bekanntes solches Werkzeug ist Valgrind. Es untersucht die Speicherbenutzung eines Prozesses zur Laufzeit. In wenigen offensichtlichen Fällen kann es ausreichen, nur den Speicherverbrauch eines Prozesses zu untersuchen.

[Bearbeiten] formale Verifikation

Durch einen Korrektheitsbeweis können insbesondere auch Speicherlecks entdeckt werden. Dieses Verfahren ist jedoch sehr Zeit-aufwendig und benötigt hochqualifiziertes Personal. Die auf Speicherlecks spezialisierte Frage kann auch Computer gestützt untersucht werden.

[Bearbeiten] Beispiele

Das bekannteste Beispiel für fehlende automatische Speicherverwaltung ist die Sprache C. Neuer Speicher wird in C-Programmen durch die Funktion malloc angefordert. Dabei liefert malloc einen Zeiger auf den Anfang des entsprechenden Speicherbereichs. Dieser Verweis ist notwendig, um den Speicher mittels geeignetem Code wieder freizugeben (mittels der Funktion free). Geht der Zeiger verloren oder wird verändert, kann der Prozess nicht mehr auf diesen Speicher zugreifen und ihn damit auch nicht freigeben.

[Bearbeiten] C

Das folgende Beispiel zeigt die Entstehung eines Speicherlecks anhand eines in C implementierten Programmes:


int main(void)
{
   int       *a, *b; /* Zeiger auf einen als Ganzzahl interpretierten Speicherbereich */
   
   /* Speicher für Zeiger reservieren. Falls Allokation fehlschlägt, Prozess beenden. */
   if( (a=(int *)malloc(sizeof(int))) == NULL)
       exit(EXIT_FAILURE);
   if( (b=(int *)malloc(sizeof(int))) == NULL)
       exit(EXIT_FAILURE);

   *a = 5;           /* Schreibt den Wert „5“ in den von a referenzierten Speicherbereich     */
   *b = 3;           /* Schreibt den Wert „3“ in den von b referenzierten Speicherbereich     */
    a = b;           /* Weist dem Zeiger a das Ziel des Zeigers b  zu. */

   /* a und b verweisen nun auf den gleichen Speicherbereich. Der zuvor von a referenzierte
    * Speicher ist damit verwaist und kann nicht mehr freigegeben werden. An dieser Stelle
    * entsteht ein Speicherleck. 
    */

   free(b);           /* Gibt den von b referenzierten Speicher frei */
   free(a);           /* Führt zu einem Fehler, da der Bereich, auf den a
                       * verweist, bereits freigegeben wurde (in der vorherigen Zeile) 
                       */
   return EXIT_SUCCESS;
}


Ab dem Schritt a = b ist es nahezu unmöglich, auf den Speicherbereich zuzugreifen, auf den a zuvor verwies. Der Bereich kann meist auch nicht mehr vom Programm freigegeben werden.

[Bearbeiten] C++

Das folgende Beispiel zeigt die Entstehung eines Speicherlecks anhand eines in C++ implementierten Programmes:

int main()
{
   int * pi = new int[5]; // Speicher für 5 Objekte vom Typ int angefordert
   delete pi;             // Speicher wird versehentlich nur für das erste Objekt freigegeben 
   return 0;
}
//Korrekt: delete[] pi;

[Bearbeiten] Automatische Speicherbereinigung

Das folgende Beispiel zeigt das Versagen des Ansatzes der automatischen Speicherbereinigung im Pseudocode:

PROCEDURE main
 LIST a
 LOOP
  a.INSERT(1)
  IF DATE() == START_TIME()+10000 THEN BREAK
 END
END

Man sieht hier deutlich, dass der Speicherbedarf ständig anwächst. Unter der Annahme, dass der zunehmende Speicherbedarf selbst nicht Zweck des Programms ist, handelt es sich also um ein Speicherleck, da gar kein lesender Zugriff auf die Listen-Einträge erfolgt. Dieser Fehler wäre recht leicht durch statische Analyse zu erkennen, während aber der Graph aus Referenzen und Speicherbereichen den Fehler nicht erkennen lässt.

[Bearbeiten] Weblinks

[Bearbeiten] Quellen

    THIS WEB:

    aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - be - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - closed_zh_tw - co - cr - cs - csb - cu - cv - cy - da - de - diq - dv - dz - ee - el - eml - en - eo - es - et - eu - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gd - gl - glk - gn - got - gu - gv - ha - haw - he - hi - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mg - mh - mi - mk - ml - mn - mo - mr - ms - mt - mus - my - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - rm - rmy - rn - ro - roa_rup - roa_tara - ru - ru_sib - rw - sa - sc - scn - sco - sd - se - searchcom - sg - sh - si - simple - sk - sl - sm - sn - so - sq - sr - ss - st - su - sv - sw - ta - te - test - tet - tg - th - ti - tk - tl - tlh - tn - to - tokipona - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu

    Static Wikipedia 2008 (no images)

    aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - bcl - be - be_x_old - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - co - cr - crh - cs - csb - cu - cv - cy - da - de - diq - dsb - dv - dz - ee - el - eml - en - eo - es - et - eu - ext - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gan - gd - gl - glk - gn - got - gu - gv - ha - hak - haw - he - hi - hif - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kaa - kab - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mdf - mg - mh - mi - mk - ml - mn - mo - mr - mt - mus - my - myv - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - quality - rm - rmy - rn - ro - roa_rup - roa_tara - ru - rw - sa - sah - sc - scn - sco - sd - se - sg - sh - si - simple - sk - sl - sm - sn - so - sr - srn - ss - st - stq - su - sv - sw - szl - ta - te - tet - tg - th - ti - tk - tl - tlh - tn - to - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu -

    Static Wikipedia 2007:

    aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - be - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - closed_zh_tw - co - cr - cs - csb - cu - cv - cy - da - de - diq - dv - dz - ee - el - eml - en - eo - es - et - eu - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gd - gl - glk - gn - got - gu - gv - ha - haw - he - hi - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mg - mh - mi - mk - ml - mn - mo - mr - ms - mt - mus - my - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - rm - rmy - rn - ro - roa_rup - roa_tara - ru - ru_sib - rw - sa - sc - scn - sco - sd - se - searchcom - sg - sh - si - simple - sk - sl - sm - sn - so - sq - sr - ss - st - su - sv - sw - ta - te - test - tet - tg - th - ti - tk - tl - tlh - tn - to - tokipona - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu

    Static Wikipedia 2006:

    aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - be - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - closed_zh_tw - co - cr - cs - csb - cu - cv - cy - da - de - diq - dv - dz - ee - el - eml - en - eo - es - et - eu - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gd - gl - glk - gn - got - gu - gv - ha - haw - he - hi - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mg - mh - mi - mk - ml - mn - mo - mr - ms - mt - mus - my - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - rm - rmy - rn - ro - roa_rup - roa_tara - ru - ru_sib - rw - sa - sc - scn - sco - sd - se - searchcom - sg - sh - si - simple - sk - sl - sm - sn - so - sq - sr - ss - st - su - sv - sw - ta - te - test - tet - tg - th - ti - tk - tl - tlh - tn - to - tokipona - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu