Speicherhunger

Wir haben ein Speicherleck! (oder doch nicht?) Konkreter Fall: Der Kunde meldet sich und beschwert sich über den exorbitanten Speicherverbrauch der Anwendung. Beigelegt hat er einen Screenshot vom Task Manager.

Was wird eigentlich im Task Manager angezeigt?

Der Task Manager zeigt die sog. "Working size" des Prozesses an. Dies bezeichnet den derzeit real (physikalisch) allokierten Speicher der Anwendung. Dieser "Speicherverbrauch" ist aber aus folgenden Gründen irreführend und sollte nicht (oder nur als grober Anhaltspunkt) für die Performance der Anwendung herangezogen werden:

  • Der Speicher wird von Windows gemäß der Priorisierung allokiert. Minimiert man die Anwendung, kann man sofort sehen wie der Speicherverbrauch zurückgeht.
  • .NET Anwendungen laufen in einer sog. "Sandbox", der .NET Runtime Umgebung. Diese ist auch in der angegebenen Speichermenge enthalten. Die eigentliche Anwendung macht also nur einen Teil dieses Speicherverbrauchs aus.
  • Laufen mehrere .NET Anwendungen gleichzeitig, können diese Teile der .NET Runtime Umgebung gemeinsam nutzen.

Ein besserer Anhaltspunkt für den Speicherverbrauch sind die sog. "private bytes". Dies bezeichnet die Menge an Speicher, die von der Anwendung nicht mit anderen Anwendungen geteilt werden kann. Der Task Manager kann diese jedoch nicht anzeigen. (Das gelingt jedoch mit dem ProcessExplorer oder perfmon (Start -> Ausführen -> Perfmon). Diese Zahl ist jedoch auch mit Vorsicht zu genießen: Sie bezeichnet sowohl aktiven als auch ausgelagerten (paged) Speicher, d.h. Hauptspeicheranteile, die aufgrund von Inaktivität auf die Festplatte ausgelagert wurden. Steigen die "private bytes" im Laufe der Zeit immer weiter an, ist ein Speicherleck vorhanden. Dies muß jedoch über einen langen Zeitraum beobachtet werden, da die Speicherverwaltung von der .NET Runtime durchgeführt wird und es teilweise recht lange dauert, bis Objekte wieder freigegeben werden (besonders wenn sie ausgelagert sind).

WTF?!

The Daily WTF ist eine unterhaltsame Seite für den geneigten Entwickler. Hier werden die grusligsten Fundstücke aus dem Programmiereralltag ausgestellt. Wenn es nur nicht so realistisch wäre..
Leider trifft man hin und wieder auf eigene Werke aus früheren Zeiten, die ebenso die Qualität hätten, in diese Galerie des Grauens aufgenommen zu werden. Man sollte daher vielleicht nicht zu vorschnell sein, ein harsches Urteil abzugeben. Wenn man in ein großes, unübersichtliches Projekt geworfen wird, produziert man anfänglich zwangsläufig eine Menge Unfug. Das hat damit zu tun, daß eigentlich keine Zeit vorhanden ist, die gesamte Funktionsweise zu verstehen. Dann wird kopiert & eingefügt, das es eine Freude ist. Aber was soll man machen? Die Aufgabe muß irgendwann fertig werden. Der entscheidende Punkt ist eben, am Ball zu bleiben und den vergangenen Unfug möglichst auszumerzen. Ebenso trifft man häufig auf Stellen, die auf den ersten Blick als grober Unfug aussehen, sich bei näherer Betrachtung aber oft als einzig mögliche Lösung (oder schmerzlosester Workaround) entpuppen. Hatte ich auch schon mal bei Joel gelesen, daß fehlerbereinigter Code oft grauenhaft aussieht. Muß ihm Recht geben. Dann wundert mich allerdings, warum noch so viele Bugs drin sind..

Am (Programmcode-) Wühltisch

Exceptions treiben mich noch irgendwann mal zum Wahnsinn. Damit ich herausfinde wo es kracht, muß ich im Debugger "Break on Exception" aktivieren. Dann bleibt er stehen wenn eine auftritt, auch wenn sie behandelt wird. Jetzt ist aber der Code gerammelt voll mit Aktivitäten wie:

try {
// lade irgend ein bitmap
..
}
catch( .. ) { .. }

Auf den Entwicklungsmaschinen und beim Kunden gibt es oft diese Bitmaps nicht. Macht aber auch nichts, ist ja nur eye candy. Jetzt kann ich entweder o.g. Einstellung wieder deaktivieren oder endlos "continue" klicken, bis der Ausführung irgendwann einmal an einer interessanten Stelle angekommen ist.
Ok, das kann man jetzt als eine lästige Nerverei abtun. Aber hier steckt noch ein viel fundamentaleres Problem dahinter. Das Abfangen der Exception bewirkt nämlich, daß der möglicherweise komplett verbuggte Code *hinter* der die Exception auslösenden Stelle nie ausgeführt wird. Passiert das eines Tages doch (z.B. beim Kunden), wundert man sich über heitere Nebeneffekte. Dahinter steckt die Denkweise, Exceptions wie gotos zu verwenden. Ich finde das grauenhaft.
Warum nicht so

if(File.Exists(filename)) {
// lade bitmap ....
}

Daher sollte man o.g. Code einfach schnell vergessen. Die Regel muß einfach lauten "wirf nur dann, wenn es wirklich was zu werfen gibt!" (und dann sollte es auch OK sein, wenn das Programm mit einem schönen Exceptiondialog abrauscht).

Web 2.0

Heute ein paar Links für den geneigten Webentwickler:

  • Ajax in 30 Sekunden. Gnadenlos mal wieder der Unterschied zwischen dem Hype und zugrunde liegenden Technologie. Es ist ein Knüller, wie einfach es funktioniert. Umso bizarrer das ganze Tohuwabohu das derzeit stattfindet. Leute, es ist zwar nett, aber bleibt mal auf dem Teppich.
  • Abgefahrenes Javascript, um Bilder auf einer Website darzustellen. Ich gebe zu, daß ich JavaScript lange unterschätzt habe, aber man kann schöne Sachen damit machen.
    Das Ganze sieht dann z.B. so aus (yo, klick das Bild an):
    (Im Firefox ist es allerdings noch besser).

Sterne (UPDATE) https://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f.gif

Es hat mir keine Ruhe gelassen, drum gibt es jetzt die Sterne in beliebiger Farbe (gd sei Dank). Außerdem ist man jetzt nicht mehr auf 5 Sterne bzw. 10 Punkte beschränkt.

Der alte Aufruf funktioniert wie gehabt, der neue geht so:

Stern(punkte,gesamtpunkte,rot,grün,blau). Also

Stern(13,20,200,150,50) ergibt SternSternSternSternSternSternSternSternSternStern (13 von 20 irgendwie komisch braunen Sternen (pfui!))
oder
Stern(3,6,50,250,100) ergibt SternSternStern (3 von 6 ziemlich grünen)

Die erzeugten Files werden gecacht, es ist also kein großes Performance-Problem.

Sterne statt Punkte

Mein obskures Wertungssystem schmeiß ich über Bord. Ab jetzt gibt es Sterne! Und zwar
goldene: https://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_n.gif
rote: https://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f_red.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f_red.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f_red.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_h_red.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_n_red.gif
blaue: https://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f_blue.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f_blue.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f_blue.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_n_blue.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_n_blue.gif
graue: https://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f_grey.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_f_grey.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_h_grey.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_n_grey.gifhttps://www.puls200.de/wp-content/plugins/Sterne/img/icon-rating-star_n_grey.gif
Aha. Dafür habe ich ein kleines WordPress Plugin zusammengehackt. Ziemlich billig, aber recht praktisch, da ich im laufenden Text nur noch z.B. " S t e r n ( 8 , g ) " tippen muss und schon habe ich z.B. 4 (von 5) goldenen Sternen am Start. Meine Skala geht also von 0-10. Man könnte natürlich noch weitere Sternfarben hinzufügen. Oder noch alberner, die Farbe der Sterne mit gd zur Laufzeit erst einstellen. Dann könnte man loslegen mit S t e r n (8 , 255 , 0, 0) für 4 von 5 roten Sternen. Aber so reicht das erstmal. Was bedeuten die Sternfarben?
- Gold: Standardfarbe, das beurteilte Objekt ist was für die breite Masse
- Blau: interessant für Leute mit speziellem Interesse, Geheimtip
- Grau: eher unbedeutend. Wäre früher das große "C" gewesen. Es kann sich also zwar um etwas Solides handeln, aber wen interessierts?
- Rot: Diese Farbe wird man nur ganz selten sehen. Und wenn, dann handelt es sich das Objekt der Begierde um einen echten Knaller. Begierde, halt ;-)

Carpe Diem (II)

Es gibt so eine Art Qualitätskurve, auf der man Software ansiedeln kann. Am einen Ende findet man Werkzeuge für den Einmalgebrauch, schnell zusammengeschustert ohne Rücksicht auf Stil und Speicherlecks, Hauptsache, die Aufgabe läuft irgendwie durch. Danach kommen eigene Tools für den Hausgebrauch, dann vielleicht Software für Einzelkunden oder Unternehmenssoftware, später sog. "Shrinkwrap", also massentauglicher Kram der im Mediamarkt in den Regalen steht und ganz am Ende Firmware und Konsolenspiele. Wenn man für das jeweilige Produkt einen festen Zeitaufwand zugrunde legt wird man feststellen, daß sich die Aufgabenanteile für unterschiedliche Tätigkeiten wie Konzeption, Implementierung und Test auch entlang dieser Kurve verschieben.

Das fiel mir neulich bei einem Gespräch mit einem Kollegen auf, bei dem es darum ging, daß wir nicht sicher wissen, welche Teile des Codes überhaupt verwendet werden bzw. welche Teile der Anwendung der Kunde überhaupt nutzt. Wenn wir jetzt Computerspiele entwickeln würden, hätten wir da ein großes Problem. Tun wir aber nicht. Und das beste: Wir haben nicht einmal Zeit, es herauszufinden. Tests auf dem Niveau von Shrinkwrap würden bei uns Bugs und Inkonsistenzen in enormer Anzahl zutage fördern. Aber es gibt keinen Vorteil, wenn viel Zeit verbraucht wird und der betreffende Bereich der Anwendung nie vom Kunden ausgeführt wird. Ein anderes Beispiel ist das Refakturieren. Damit bezeichnet man das Umschreiben von größeren Programmteilen mit dem Ziel, eine Vereinfachung, Verbesserung und in vielen Fällen auch quantitative Verringerung des Programmcodes herbeizuführen. Die Vorteile bleiben zwar, dennoch bringt eine Refakturierung in unserem Bereich mehrere Nachteile mit sich:

  • Der refakturierte Code muß erneut getestet werden
  • Es ist schwer sicherzustellen, daß durch die Änderungen keine unerwarteten Nebenwirkungen auftreten
  • Die Änderungen müssen an die Kollegen kommuniziert werden
  • Durch die enorme Menge vorhandenen Codes sind i.d.R. fast immer größere Änderungen erforderlich. Der dafür benötigte Zeitaufwand kann nicht immer fakturiert werden. Falsch. Kann eigentlich nie fakturiert werden.

Ein guter Freund von mir ist ein regelrechter Code-Ästhet. Nichts soll redundant sein, alles effektiv und glatt gebügelt. Er hätte mit dem Kram hier nicht viel Freude.
Worauf ich hinaus will: Man kann zwar denselben Beruf haben, aber seinen Tag trotzdem fast komplett mit andere Dingen verbringen.

.NET?! Waas i net!

Wenn man eingestellt werden will, möchte man immer die besten Antworten auf alle möglichen Fragen parat haben. Möchte man selber jemand einstellen, hätte man am liebsten die richtigen Fragen. Fragen, mit denen man wenigstens im groben die fachliche Eignung des Kandidaten feststellen kann. Nach dem ich gehört habe, daß Fragen a'la How would you move Mount Fuji nicht mehr in sind, und andere behaupten, daß man im Bewerbungsgespräch die fachliche Kapazität quasi gar nicht feststellen kann, bin ich heute über einen Blog Eintrag gestolpert, der eine Menge guter Fragen bereithält, um .NET Fachwissen zu testen. Ich muß zugeben, daß ich auf einige Fragen auch keine Antwort wusste, vor allem im ASP Teil. Wichtig ist es eben sicherzustellen, konzeptionelle Fragen zu stellen und kein prokeliges Detailwissen abzufragen. z.B. "What does this do? sn -t foo.dll" ist Unfug, den das weiß nur jemand, der schonmal mit Keys und Assemblies hantiert hat.

Verbogene Schraubenzieher

Im Joel-Test gibt es den Punkt 9: "Do you use the best tools money can buy?" über den ich mich heute einmal ein paar Zeilen lang auslassen will. Ich dachte eigentlich bisher, daß das einer der unwichtigsten Punkte ist. Irgendwie kriegt man den Kram doch auch mit vi und ein paar l33ten Skripten aus der Tür! Nun ja, im Prinzip schon. Wie immer hängt es äußerst stark davon ab, womit man sein Geld verdient. Bearbeitet man nur einmal im Monat ein Bild (und spielen professionelle Ansprüche keine große Rolle), reicht vielleicht eine 8 Jahre alte Version von Corel PhotoPaint (hallo, Jan! ;-) ). Bearbeitet man XML Dateien mit 5 Zeilen geht das auch noch in Notepad. Versetzt man sich einmal in den Heimwerkerbereich gibt's da keine Frage: Jeder hat schonmal ein 0,99 € Schraubenziehersortiment an der Kasse mit in den Wagen geworfen. Irgendwann später findet man möglicherweise eine passende Schraube. Freudig juchzend schnappt man sich den mehr oder weniger passenden Dreher nur um ein paar Sekunden später festzustellen, daß die Schraube den Dreher gedreht hat statt andersrum. Ärger! Klar passiert das nicht mit den Chrom-Vanadium Drehern für 15 € das Stück. Nur wer kann sich davon ein Sortiment leisten? Aber hat man das richtige Gerät freut man sich, die Arbeit geht fix und sauber, hinterher ist nix kaputt. "If you have a shiny new hammer, every problem looks like a nail..".
Zurück in der Welt der Programmentwicklung verhält es sich ganz ähnlich. Der Hauptunterschied besteht darin, daß die richtig guten Werkzeuge exorbitant teuer sind (im Verhältnis zu den einfacheren) und daß der Alterungsprozeß des Werkzeugs so schnell ist, daß man gut daran tut den richtigen Moment abzupassen, in dem der entsprechende Dreher auch gebraucht wird. Der nächste entscheidende Punkt ist die Zeitersparnis. Je nach dem welcher Stundensatz zugrunde gelegt wird kann man leicht ausrechnen, ab welchem Zeitpunkt die Investition amortisiert ist. Dann noch der Motivationsschub, in Zahlen schwer auszudrücken. Es fühlt sich einfach ungemein produktiver an, mit einem passenden Werkzeug zu hantieren.
Noch einfältiger ist es, bei der Hardware zu sparen. Wenn ich mir überlege, wieviel Zeit meines Arbeitslebens mit der Betrachtung der Sanduhr verdüdelt wurde, oder wieviel Zeit dabei draufging, irgendwelche alten Rechner wieder zu Routerdiensten und ähnlichem zurechtzukonfigurieren, hätte man einige moderne Maschinen erstehen können. Andrerseits, wann könnte ich sonst diese unterhaltsamen(??!) Postings erstellen, wenn nicht in der Zeit, in der der Compiler glüht?
So, die Moral von der Geschichte: Bei Investitionen in Werkzeuge läßt sich sehr schnell am falschen Ende sparen (vor allem wenn man sich die Investition spart... rofl).

Puls200 Shell Extension

Aus der Not Faulheit heraus geboren wurde dieses kleine Werkzeug: Die Puls200 Shell Extension. Es wurde mir langsam lästig: Bild auswählen, Grafikprogramm starten, skalieren, unter einem anderen Namen speichern lokal im Web-Backup, FTP client starten, hochladen und hoffen daß der Link funktioniert. No more!
Jetzt kann man direkt im Explorer mit einem Kontextmenü-Rechtsklick alle diese Schritte auf einmal ausführen und die Einstellungen verändern. Wenn das Tool fertig ist, hängt übrigens der Link in der Zwischenablage und kann leicht mit CTRL-V in das Posting kopiert werden. Ist das nicht entzückend? ;-)
Leider habe ich noch keine Zeit gefunden, einen Installer zu konstruieren (wie war das eben mit der Faulheit?! ;). Das einzige, was benötigt wird, ist, daß das regasm.exe Tool auf dem System vorhanden ist (Teil des .NET Framework).