Laden...

Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb

Erstellt von PoWl vor 7 Jahren Letzter Beitrag vor 7 Jahren 16.844 Views
P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren
Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb

Ich habe hier eine WPF Slideshow, die im 3-Sekunden Takt einem von zwei Image-Steuerelementen eine BitmapImage als Source zuweist, welches aus Bildern, die auf der Festplatte liegen, erzeugt wird. Das Programm läuft zwar auf einem hardwareschwachen Tablet, läuft aber über Stunden hinweg problemlos durch. Ca. einmal am Tag passiert es jedoch, dass das Programm einfach abstürzt. Ich hab das mal untersucht, indem ich bisher nicht-gefangene Exceptions nun zentral abfange und in einer Log-Datei speichere. Dabei kam folgendes raus:

Fehlermeldung:
DispatcherUnhandledException: System.IO.IOException: Nicht genügend Quoten, um den angeforderten Dienst auszuführen.

bei System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
bei System.IO.__ConsoleStream.Write(Byte[] buffer, Int32 offset, Int32 count)
bei System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
bei System.IO.StreamWriter.Write(String value)
bei System.IO.TextWriter.Write(Int32 value)
bei System.IO.TextWriter.WriteLine(Int32 value)
bei System.IO.TextWriter.SyncTextWriter.WriteLine(Int32 value)
bei System.Console.WriteLine(Int32 value)
bei P_Slideshow_Vorabversion.MainWindow.<ImageChangeTimer_Tick>d__24.MoveNext()
--- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde ---
bei System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_0(Object state)
bei System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
bei System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)

Das ganze lässt sich auf diese Codestelle zurückführen, welche im Timer-Tick Event alle 3 Sekunden ausgeführt wird und dem Image-Steuerelement ein neues BitmapImage als Source zuweist:


imageElements[currentImageElement].Source = new BitmapImage(new Uri(System.IO.Path.Combine(mediaDir, imageFiles[currentImageFile])));

Nach kurzer Recherche bedeutet wohl "Nicht genügend Quoten" so viel wie "zu wenig Systemresourcen". Also zu wenig RAM wohl? Das ist aber nicht der Fall. Im laufenden Betrieb genehmigt sich meine Anwendung dauerhaft nur 64Mb RAM. Laut Taskmanager sind auch nur 61% des RAMs belegt, und selbst wenn, dann gäbe es da ja noch die Auslagerungsdatei. Zudem tritt der Fehler nur völlig sporadisch auf. Ich erzeuge da ständig BitmapImage-Objekte, welche ich nie auflöse. Aber der Garbage-Collector sollte sich ja nach einer Weile darum kümmern, die nicht von meinen beiden Image-Steuerelementen gerade geladenen und somit verwaisten BitmapImage-Objekte wieder aus dem RAM zu schmeißen.

Klar, ich könnte jetzt die Exception an entsprechender Stelle adäquat abfangen aber lieber wäre es mir, das Problem an der Wurzel zu packen. Wie kann ich das weiter untersuchen? 🤔

16.806 Beiträge seit 2008
vor 7 Jahren

Typisches Beispiel, wieso man immer mit einem englischen System als Entwickler unterwegs sein sollte: bescheiden übersetzte Fehlermeldungen.

Ich würde mal aktuell davon ausgehen, dass mit Quoten das Quota gemeint ist.
Also zB. die durch administrative Einschränkung von Speicherplatz auf der Festplatte. Sehr verbreitet auf Terminalservern oder bei Unternehmen.

Der Taskmanager ist keine verlässliche Quelle für den tatsächlich verwendeten Arbeitsspeicher.
Dein StackTrace passt nicht zu Deiner analysierten Code-Stelle. Im StackTrace ist ein eindeutiges Schreiben eines Streams zu sehen zusammen mit einem "maybeFullpath".
Spricht also für die Quota-Situation, also dass Dir irgendwo der verfügbare Festplattenspeicher ausgeht.

Hast Dir denn mal die InnerException angeschaut?

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Danke. Nun sind meine 3 Tablets, auf denen die Software gerade läuft, ja ganz normale Consumer-Geräte mit frisch installiertem Windows 10 Home und haben alle drei noch mehrere 100mb Festplattenspeicher übrig 🤔

Dein StackTrace passt nicht zu Deiner analysierten Code-Stelle. Im StackTrace ist ein eindeutiges Schreiben eines Streams zu sehen zusammen mit einem "maybeFullpath".
Spricht also für die Quota-Situation, also dass Dir irgendwo der verfügbare Festplattenspeicher ausgeht.

Hm ja das sehe ich. Ich dachte nur, dass
"bei P_Slideshow_Vorabversion.MainWindow.<ImageChangeTimer_Tick>d__24.MoveNext()"
impliziert, dass es im Timer-Tick Event auftritt? Ist das nicht so?

Darüberhinaus gibt es in meinem gesamten Code auch keine Stelle, an der einfach so ein Schreibzugriff erfolgt. Und meine Logging-Funktion wird erst dann aufgerufen, nachdem die Exception schon geworfen wurde, um diese zu loggen, was ja auch funktioniert.

Die InnerException habe ich noch nicht untersucht. Ich muss jetzt erst mal abwarten, bis der Fehler wieder auftritt.

5.657 Beiträge seit 2006
vor 7 Jahren

Hi PoWl,

Ich erzeuge da ständig BitmapImage-Objekte, welche ich nie auflöse. Aber der Garbage-Collector sollte sich ja nach einer Weile darum kümmern, die nicht von meinen beiden Image-Steuerelementen gerade geladenen und somit verwaisten BitmapImage-Objekte wieder aus dem RAM zu schmeißen.

Das ist keine gute Idee. Um die Freigabe von nicht verwalteten Resourcen wie Bitmaps mußt du dich selbst kümmern, z.B. mit der IDisposible.Dispose-Methode oder mittels using.

Weeks of programming can save you hours of planning

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Hm sehr gerne, aber der Garbage-Collector kommt damit scheinbar ganz gut zurecht. Immerhin bläht sich meine Anwendung ja über die Stunden, die sie läuft, nicht immer weiter auf. Das ist natürlich nicht besonders edel aber es schien bisher auch nicht weiter zu stören. Aber was ist, wenn ich das BitmapImage-Objekt, nachdem ich es dem Image-Steuerelement als Source zugewiesen habe, direkt wieder zerstöre? Verschwindet dann das Image? oder kann ich das einfach so tun?

5.657 Beiträge seit 2006
vor 7 Jahren

Der GarbageCollector kümmert sich nicht um nicht-verwaltete Resourcen, deshalb heißen sie nicht-verwaltet: Cleaning Up Unmanaged Resources.

Und nein, natürlich kannst du ein Objekt nicht mehr verwenden, nachdem du den Speicher dafür freigegeben hast.

Weeks of programming can save you hours of planning

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Warum stellt ein Bitmap eine nicht-verwaltete Ressource dar? BitmapImage stellt keine Dispose() Methode bereit.

Ich habe zwar folgenden Codefetzen entdeckt:

                    var bitmap = new BitmapImage();
                    var stream = File.OpenRead(System.IO.Path.Combine(mediaDir, imageFiles[currentImageFile]));
                    bitmap.BeginInit();
                    bitmap.CacheOption = BitmapCacheOption.OnLoad;
                    bitmap.StreamSource = stream;
                    bitmap.EndInit();
                    stream.Close();
                    stream.Dispose();

Aber der ändert ja nichts daran, dass das BitmapImage-Objekt im Speicher bleibt. Ich sehe aber auch nach wie vor keine Notwendigkeit, mich darum explizit zu kümmern, denn ich habe ja kein Memory-Leak. Die meisten Bilddateien, welche ich zuvor im Programm geladen hatte, kann ich auch während das Programm noch läuft, im Windows Explorer löschen. D.h. die sind nicht durch mein Programm blockiert.

16.806 Beiträge seit 2008
vor 7 Jahren

Deine Argumentation stimmt so nicht, PoWl.
Es gibt nicht nur eine beschränkte Anzahl von RAM-Ressourcen, die Du verwenden kannst, sondern auch Windows Handles.
Jede Allokierung eines Bildes nimmt auch ein Handle in Anspruch. Gibst Du dieses nicht frei, dann wird das Handle auch nicht freigegeben.
Kommst Du an das Limit der verfügbaren Handles, dann knallts - wie zB. es hier der Fall sein kann.

Ich bin kein WPF Profi, aber wenn man sich die MSDN so durchliest, dann muss man auch ein BitmapImage wieder aktiv freigeben; ansonsten gibts Memory Leaks und/oder offene Handles.
Dass Du nicht die Notwendigkeit siehst, dass Du Dich drum kümmern müsst - nimm mir das jetz nich übel, würde ich jetzt direktweise darauf zurückführen, dass Du nicht weisst, was Du da im Hintergrund wirklich tust 😃

Nur weil Du etwas im Explorer löschen kannst heisst das nicht, dass Du nicht ein Handle drauf und damit ein Leak hast.

PS: Deine Fehlermeldung auf Englisch lautet> Fehlermeldung:

Not enough quota is available to process this command

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Hm ok! 😃
Kann ich mir die verwendeten Handles irgendwo angucken? Die müssten ja dann im Laufe der Zeit kontinuierlich steigen.

Ist der Codefetzen, so wie ich ihn nun gezeigt habe, ausreichend?

Wie gesagt, das BitmapImage stellt kein Dispose() bereit. Ich weiß nun nicht, wie ich mich darum kümmern kann.

16.806 Beiträge seit 2008
vor 7 Jahren

Alles, was Dispose implementiert (zB streams), sollte man mit Hilfe eines using() nutzen.
Das zeigt auch, dass Du Dir den Unterschied von Close() und Dispose() bei den Stream-Klassen mal anschauen solltest....

Und dass Du das nun fragst zeigt auch, dass Du Dir meinen verwiesenen Link nicht angeschaut hast, und damit auch offensichtlich nicht über Freeze() gestolpert bist....
Keine 2 Minuten später kam Deine Antwort. Du kannst Dir also den Link gar nicht angeschaut haben; vermutlich haste Dir nicht mal meinen Beitrag ganz durchgelesen.
Da frag ich mich dann schon, wieso ich mir die Mühe mach, Dir den Link raus zu suchen...

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Ja danke =), den Link kannte ich bereits deswegen war ich so schnell. Du meinstest wohl auch StackOverflow und nicht MSDN?

Die Freeze-Methode habe ich mittlerweile (ohne dies bereits erwähnt zu haben) auch implementiert. Allerdings würde ich wirklich gerne mal nachprüfen, ob ich irgendwelche Ressourcenleaks habe oder nicht. Ich möchte ja nicht nur aus Angst alle möglichen Codeteile einbauen, ohne dass diese tatsächlich notwendig wären. Ich möchte verstehen, was ich da tue. Ich weiß nur, dass es alle paar Tage mal eine Exception beim laden des Bildes gibt.

Mittlerweile sieht das ganze nun so aus:

var bitmap = new BitmapImage();
using (var stream = File.OpenRead(System.IO.Path.Combine(mediaDir, imageFiles[currentImageFile])))
{
    bitmap.BeginInit();
    bitmap.CacheOption = BitmapCacheOption.OnLoad;
    bitmap.StreamSource = stream;
    bitmap.EndInit();
    bitmap.Freeze();
    stream.Close();
}

imageElements[currentImageElement].Source = bitmap;

  1. bitmap.CacheOption = BitmapCacheOption.OnLoad;
    Was bewirkt das? "Caches the entire image into memory at load time. All requests for image data are filled from the memory store.", das Bild wird also aus der Bilddatei geladen und im Arbeitsspeicher gecached. Aber wird es das nicht sowieso? Bei BitmapCacheOption.Default steht "Caches the entire image into memory. This is the default value.". Wo ist der unterschied?

  2. Muss ich unbedingt einen FileStream verwenden, welchen ich hinterher mit Dispose() wieder vernichten kann, um das Bild zu laden? Ich könnte das Bild auch per bitmap.UriSource laden. So wie ich das verstehe hilft das nur, um die Datei gleich wieder freizugeben aber erzeugt keinen Leak. Oder irre ich mich?

  3. Bbitmap.Freeze()
    Ich habe schon mehrfach gelesen, dass es Memory Leaks gibt, sobald ich das BitmapImage, welches ich dem Image zuweise, nicht freeze. Aber ich kann auch nach Stunden an Laufzeit kein MemoryLeak feststellen. Bisher habe ich gelesen, dass Freeze() das von Freezable abgeleitete BitmapImage so tagged, dass es nicht mehr verändert werden kann. D.h. WPF muss es nicht kopieren, um es anzuzeigen, sondern kann es direkt aus dem Speicher verwenden. Aber wenn es nicht freezed wäre, und WPF es kopieren würde, warum sollte das dann zu irgendwelchen Leaks führen?

Ich verstehe die Zusammenhänge nicht.

Warum genau werden die von BitmapImage verwendeten Ressourcen nicht mehr freigegeben? Das sind doch alles managed Objekte? Warum gibt es kein Dispose()?

16.806 Beiträge seit 2008
vor 7 Jahren

Der Stream ist kein active managed object.
Du musst hier also explizit dem GC sagen, wenn Du den Stream nicht mehr brauchst. Steams an für sich verwenden eben Windows Handles, die keine managed objects darstellen.

Dein BitmapImage ist zwar managed, aber will eben die StreamSource haben. Da BitmapImage für Dich nicht den Stream verwaltet, musst Du ihn verwalten.
In der Regel ist das bei allen Objekten so, die den Stream nur via Property und nicht via Konstruktor entgegen nehmen.

Wenn man sich nun 5 Minuten Zeit nimmt und in den Quellcode von EndInit schaut, dann sieht man, dass dabei FinalizeCreation aufgerufen wird.

Es erstellt sich also selbst ein BitmapImage aus Deinem Stream, das es dann auch selbstständig verwalten kann.
BitmapImage arbeitet dabei, wie man sehen kann, mit einer BitmapSource, das das Bild als PixelArray vorhält und dabei keine unmanaged reference hat und somit auch nichts zum disposen hat.
Daher gibt es keine Dispose-Methode.
Entsprechend bist Du eben für den Stream verantwortlich. Gibst Du ihn explizit nicht frei, dann kommst Du irgendwann im Laufzeit der Applikation an die Grenze der verfügbaren Handles -> Big Bang.

Wenn Du es also verstehen willst, dann schau Dir ab und zu auch mal den Quellcode von .NET an, wenn die Doku nicht ausreicht.
Inwiefern die Options hier eine Relevanz spielen weiß ich nicht. Müsste ich jetzt auch wieder in den Quellcode schauen, ob das überhaupt an der entsprechenden Stelle abgefragt wird; aber da Du nun weisst, wie man in den Quellcode schaust, kannste das ja auch selbst machen 😉

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Das ist ja interessant, ich wusste gar nicht, dass man so ohne weiteres auf den Quellcode Zugriff hat. Wir kommen hier aber ein wenig vom Thema ab. An keiner Stelle meines Programms habe ich jemals einen Stream erzeugt, ohne diesen wieder freizugeben.

Dein BitmapImage ist zwar managed, aber will eben die StreamSource haben. Ok. jetzt gibt es ja wie gesagt auch die Möglichkeit, dem BitmapImage keine StreamSource sondern eine UriSource (im Konstruktor) zu übergeben, so wie ich das anfangs gemacht habe. Damit müsste sich ja das BitmapImage darum kümmern, sich die Daten aus der Datei zu holen und die entsprechenden Ressourcen wieder freizugeben. Das folgt allein schon als logischer Schluss aus der Tatsache, dass ich überhaupt keine Möglichkeit habe, mich von Außen darum zu kümmern, also wird BitmapImage an dieser Stelle selber die "Drecksarbeit" machen.

Ich sehe in der BitmapImage-Klasse folgendes:


        public BitmapImage(Uri uriSource) : this(uriSource, null)
        {
           
        }

       public BitmapImage(Uri uriSource, RequestCachePolicy uriCachePolicy) : base(true)
        {
            if (uriSource == null)
            {
                throw new ArgumentNullException("uriSource");
            }
 
            BeginInit();
            UriSource = uriSource;
            UriCachePolicy = uriCachePolicy;
            EndInit();
        }

d.h. der Einzeiler (der Code, den ich anfangs verwendete, mit dem die Exception irgendwann auftrat)

var bitmap = new BitmapImage(new Uri(System.IO.Path.Combine(mediaDir, imageFiles[currentImageFile])));

und

var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(System.IO.Path.Combine(mediaDir, imageFiles[currentImageFile]));
bitmap.EndInit();

sind völlig äquivalent.

Unter Windows 10 habe ich im Taskmanager leider nicht mehr die Option, mir die von einem Prozess verwendeten Handles anzuschauen. Wohl aber unter Windows 7. Und dort bleibt die Anzahl an Handles die ganze Zeit über im Mittel konstant. Egal in welcher Art und Weise ich das BitmapImage erzeuge und egal ob ich Freeze() einsetze oder nicht. 🤔 Ich habe mein Programm eben extra mal so modifiziert, damit ich alle bisher vorgestellten Codevarianten per Checkbox einzeln aktivieren und deaktivieren kann. Mit keiner Variante geraten die Handles oder der RAM außer Kontrolle. Selbst mit dem Einzeiler nicht.

16.806 Beiträge seit 2008
vor 7 Jahren

Der Taskmanager ist keine verlässliche Quelle bei .NET Anwendungen für Arbeitsspeicher und Handles.
Das liegt an der Art und Weise, wie .NET mit diesen Ressourcen im Allgemeinen umgeht: How much memory does my .NET application use?
Entsprechend sei hier die Working Sets und Heap erwähnt.

Verwende entsprechend dafür vorgesehene Profiler.

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Na dann schaue ich mir mal so einen Profiler an.

Ich verstehe jedoch nicht: Wenn mein Programm ein Handle-Leak haben soll. Warum steigt dann die gesamte Anzahl an Handles im System nicht irgendwann deutlich an? Weder die Prozess-Handles noch die im gesamten System verwendeten Handles verändern sich über einen größeren Zeitraum signifikant. Der Prozess belegt laut Task-Manager immer nur um die 912 Handles. Angenommen es werden im Laufe der Stunden hunderte Handles belegt aber nie freigegeben, müsste sich das doch irgendwo bemerkbar machen, auch ohne Profiler? 🤔 Wenn ich alle 3 Sekunden ein neues Bild lade müssten das ja 28800 Handles am Tag sein. Das ist mehr als mein System insgesamt gerade anzeigt, das würde schnell auffallen.

16.806 Beiträge seit 2008
vor 7 Jahren

Du bringst das durcheinander.

Die Exception, die Du mittlerweile auf Englisch hast, besagt, dass es was mit den Quotas sind.
Dein falscher Umgang mit Ressourcen ist das andere Thema.

Jetzt _kann _es natürlich sein, dass das einfach nur ein Folgefehler ist. Aber wir haben das System nicht vor uns, sondern nur Du.
Daher bleibt uns an dieser Stelle nichts anderes als Vermutung zu erstellen und Schlüsse aus den vorhandenen Informationen hier zu ziehen.
Es kann auch was andres als die Handles sein, zB. eben die Quotas.

Haste Dir überhaupt die Mühe gemacht die englische Fehlermeldung im Zusammenhang mit WPF zu googlen?
Scheint keine Unbekannte zu sein. Und Bilder, Ressourcen und Handles scheinen hier eine Rolle zu spielen.

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

😭

Na gut, back to topic:

not enough quota is available to process this command

Dass das die besagte Fehlermeldung ist, war mir schon von Anfang an klar, obgleich du so freundlich warst, sie irgendwann hier noch mal zu übersetzen. 😉 Dementsprechend konnte ich dazu ja auch ein wenig googeln.

MSDN meint dazu:

Close some applications and try again. If you still get this message, choose System from Control Panel, then choose Virtual Memory and increase the size of your paging file.

Das spricht nun nicht gerade dafür, dass mein Festplattenspeicher begrenzt ist, sondern dass der Arbeitsspeicher ausgeht und man deshalb die Auslagerungsdatei vergrößern soll. Jedoch ist weder mein Festplattenspeicher zu knapp noch habe ich zu wenig Arbeitsspeicher frei. (Laut Task-Manager liegt die Belegung des Arbeitsspeichers bei 70% und die Auslagerungsdatei ist dynamisch. Festplattenspeicher noch >1Gb)

http://stackoverflow.com/questions/12584619/mysterious-not-enough-quota-is-available-to-process-this-command-in-winrt-port
Hier trat die gleiche Fehlermeldung bei jemandem auf, der offenbar zu viele Änderungen im Visual Tree gleichzeitig ausgeführt hat, was auf mich ja nicht zutrifft, aber weiterhin impliziert, dass der Fehler nicht zwangsläufig etwas mit dem freien Festplattenspeicher zu tun haben muss.

Instead, it was about limitations in the Windows messaging system. Apparently it is a little like a stack overflow exception, in that when you make too many changes to the visual tree all at once, [...]

Nach weiterer Recherche ergibt sich: Quotas können alle möglichen Beschränkungen sein.

[...] it sets an upper limit to the counted number of resources of a certain type. Common examples are 10,000 windows, 10,000 GDI objects, 10,000 handles.

Ich werde das ganze nun einfach mal laufen lassen und weiterhin warten, wann und wo die Fehlermeldung das nächste mal auftritt. Dieses mal logge ich auch die InnerExceptions mit.

Zum Ressourcenthema:

Am Anfang sagte MrSparkle:

Um die Freigabe von nicht verwalteten Resourcen wie Bitmaps mußt du dich selbst kümmern, z.B. mit der IDisposible.Dispose-Methode oder mittels using. Das aber funktioniert nicht, da das BitmapImage keine Dispose-Methode zur Verfügung stellt. Da ich keine Möglichkeit dazu habe muss ich davon ausgehen, dass .net sich hier selbst drum kümmert.

Weiterhin sagtest du:

Jede Allokierung eines Bildes nimmt auch ein Handle in Anspruch. Gibst Du dieses nicht frei, dann wird das Handle auch nicht freigegeben. Ich kann jedoch die Anzahl der benutzten Handles nirgendwo ansteigen sehen. Obgleich .net gleich von Anfang an den Prozess mit hunderten Handles startet, von denen möglicherweise ein Großteil gar nichts mit meinem Programm zu tun hat, so müssten die abertausende Handles, die mein Programm nach einiger Zeit in Anspruch nimmt, ja irgendwo sichtbar sein. Ich kann also keinen Leak feststellen, lediglich vermuten. Aber wie gesagt, habe ich darauf ja auch gar keinen Einfluss. Und dabei darf es, wie ich bereits erörtert habe, keine Rolle spielen, ob ich das Bild per Streamreader einlese (und den Stream wieder manuell freigebe) oder ob ich dem BitmapImage-Objekt einfach eine Uri übergebe, und es die Arbeit selbst machen lasse. Darauf muss ich mich ja verlassen können, sonst ergäbe das UriSource-Property überhaupt keinen Sinn, wenn es ein Ressourcenleak erzeugen würde.

Dein Link führt indirekt übrigens zu folgendem weiterführendem Thema:
http://stackoverflow.com/questions/11202807/garbage-collection-fails-to-reclaim-bitmapimage

There was a bug in Wpf that we were bitten by where BitmapImage objects are not released unless you freeze them.
>
was the original page where we discovered the issue. It should have been fixed in Wpf 3.5 sp1 but we were still seeing it in some situations. Try changing your code like this to see if that is the problem:

WPF 3.5 ist jedoch Schnee von Gestern. Nun behauptet der gute Mensch da, das Problem tritt immer noch, also empfiehlt es sich, weiterhin Freeze() zu nutzen. Jedoch ging es dort die ganze Zeit um Memory Leaks. Nicht um Handles oder sonstiges. Und ich kann wie gesagt kein Memory Leak beobachten. Der Prozess bläht sich nicht auf, die RAM-Auslastung des gesamten Systems bleibt konstant.

Edit: Missverständliche Passage entfernt.

16.806 Beiträge seit 2008
vor 7 Jahren

.. da fällt einem nicht mehr viel ein.

Das aber funktioniert nicht, da das BitmapImage keine Dispose-Methode zur Verfügung stellt.

auf den Satz

Um die Freigabe von nicht verwalteten Resourcen wie Bitmaps mußt du dich selbst kümmern, z.B. mit der IDisposible.Dispose-Methode oder mittels using.

Bitmap != BitmapImage.
Hier ging es um die prinzipielle Freigabe von unverwaltetet Ressourcen, wie eben es bei Bitmaps oder Streams der Fall ist.
Dein Code hat(te) hier ein Leck und bei dem Aussageinhalt bleibe ich auch.

Aber ich hab ehrlich gesagt wenig Verständnis dafür, wenn man lieber Vermutung aufsteht, statt Konsequent den Ursachen nachgeht.
In .NET gibt es nun mal Fehlermeldungen, die nicht 1:1 auch die Ursache sind. Beispiel: wird eine OutOfMemoryException auch geworfen, wenn Du noch Terabyte-Weise freien Arbeitsspeicher in Deinem so genauen Taskmanager siehst; einfach weil diese Exception eben nicht nur von unzureichendem Arbeitsspeicher ausgelöst wird, sondern zB. eben auch von unzureichenden Windows Handles. Die Exception heisst trotzdem OutOfMemoryException und nicht OutOfHandlesException. Nichts anderes kann es bei dieser DispatcherException der Fall sein. Sie beschreibt schließlich die Quota, was alles mögliche sein kann, Speicher, Handles..
Du kannst jetzt mit dieser Tatsache leben, sie akzeptieren und mit ihr arbeiten - oder so weiter machen 😃

Ich bin jedenfalls raus hier.

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Pardon, vielleicht habe ich mich falsch ausgedrückt: Ich habe lediglich das Gefühl, das Ressourcenproblem ist ein Gespenst, da es (bis auf die Exception) keine sichtbaren Anzeichen gibt. Ich wundere mich lediglich. Denk dran, ich bin ein Neuling, man vergebe mir. Einen Profiler bin ich ja auch gerade am suchen, jedoch muss ich mich da auch erst mal einarbeiten. Vielleicht liefert der mir ein paar interessante Eindrücke.

Dein Code hat(te) hier ein Leck und bei dem Aussageinhalt bleibe ich auch.

Du hast deutlich mehr Erfahrung, daher glaube ich dir das nur allzu gerne! Ich kann jedoch lediglich nicht nachvollziehen, warum das denn so ist. Ich umreiße noch mal kurz: Warum entsteht ein Leck, wenn ich das Bild über das Setzten einer UriSource lade (so wie anfangs geschehen), und warum entsteht keines, wenn ich es über die StreamSource lade (und danach den Stream manuell freigebe). Welche Legitimation hat dann die Existenz des UriSource-Properties, wenn dieses zwangsläufig ein Leck erzeugt? Oder meintest du, das fehlende Freeze() war die Ursache für das Leck?

Dass der Taskmanager hier keine Verlässlichen Angaben liefert, das glaube ich dir auch gerne. Aber wo ist der Fehler in meiner Erörterung? Hat .net die Macht, tausende Handles zu reservieren, ohne dass das im Taskmanager irgendwas davon auftaucht? Auch bei der Gesamtzahl der im System vorhandenen Handles nicht? 🤔

Sie beschreibt schließlich die Quota, was alles mögliche sein kann, Speicher, Handles.. Das habe ich ja nun wie gesagt auch bereits herausgefunden 😁 Jetzt kann ich wohl nur noch auf den Profiler setzen, der mir dann hoffentlich aufzeigen wird, wo das Leck ist. Vielleicht hast du eine Empfehlung?

16.806 Beiträge seit 2008
vor 7 Jahren

procmon.exe zur Analyse zur Laufzeit als externe Anwendung oder Dein in Visual Studio eingebauter Profiler und/oder JetBrains dotTrace / dotMemory.

So mal ne Anekdote:
Ich hatte in einem Windows Service ewig das Problem, dass ich eine Exception (weiß nicht mehr welche genau) im die Ohren bekommen hab, nach ca. 6-12h Laufzeit.
Grund war jedoch, dass ich durch einen Flüchtigkeitsfehler in einem Task einen EventHandler registriert habe.
Dadurch wurde der Task nie aufgeräumt und die dazugehörigen Objekte auch nicht.
Die Exception hatte damit nichts zutun; hat aber durch Folgefehler ausgelöst.

Ich würde hier also eher nach dem Execptiontyp statt nach der Beschreibung suchen.
Es kann, wie Du schon meintest, auch überhaupt nichts mit den Ressourcen zutun haben und wir haben hier einfach ebenfalls einen weiteren Flüchtigkeitsfehler gefunden.
zB weil Du irgendwas asynchron ausführst ohne es zu locken oder sowas. Einfach Race Conditions, an die man nicht denkt.

Ich vermute, dass dieser Fehler hier im Forum als Zufall gefunden wird; also nach dem Motto "hast Du evtl. das und das?"
"Oh stimmt, da hab ich was, das könnte es sein!".

Nein, .NET hat nicht die Macht, Handles zu erstellen, ohne, dass diese im Task Manager auftauchen.
Im Gegenteil: Handles können nur durch die Win32 API erstellt werden, die Windows zur Verfügung stellt. .NET ist hier nur ein Konsument dieser Windows API.
Die Anzahl der Handles müsste jedoch im 100er- oder gar 1000er-Bereich hin und her springen, was zumindest bei mir und hier aktuell auf meinem Windows Server 2016 auch der Fall ist. Daher ist dabei gar keine verlässliche Quelle zu identifizieren, wer diese Handles (de)registriert und für diese 100er-Schwankung verantwortlich ist.

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Ja, die Anzahl der Handles springen in der Tat im 100er-Bereich hin und her. Müsste sich bei einem Handle-Leak nicht aber insgesamt gesehen eine langfristige Tendenz nach Oben abzeichnen?

16.806 Beiträge seit 2008
vor 7 Jahren

Prinzipiell ja, aber nicht immer sofort erkennbar.

M
184 Beiträge seit 2012
vor 7 Jahren

Hast du dir im Taskmanager auch schon mal die GDI-Objekte angesehen? Ich weiß nicht, ob WPF überhaupt irgendwie GDI benutzt, aber unter Windows Forms könnte das auch ein möglicher Grund sein.

P
19 Beiträge seit 2016
vor 7 Jahren

Wenns ein speicher Problem ist kann es gut sein das du die WPF Bindings nicht richtig implementiert hast.
Für jede klasse auf die gebunden wird, die dennoch nicht 'INotifyPropertyChanged' implementiert wird per Reflection ein PropertyBinding erzeugt welches du nie aus dem Arbeitsspeicher bekommst.
Schau mal nach ob du das 'INotifyPropertyChanged' irgendwo vergessen hast.

Um nachzuschauen Wo & Ob du ein speicher Problem hast kannst du die DiagnosticTools vom Visual Studio verwenden oder Manuell eine Weakreference in einer Liste ablegen & nach einer zeit schauen ob bei den WeakReference's noch IsAlive auf true steht.

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Hast du dir im Taskmanager auch schon mal die GDI-Objekte angesehen? Ich weiß nicht, ob WPF überhaupt irgendwie GDI benutzt, aber unter Windows Forms könnte das auch ein möglicher Grund sein.

Also im Taskmanager / Process Monitor werden bei den Handles, GDI-Objekten und Threads über den gesamten Zeitraum eine nahezu konstante Zahl angezeigt. Wie Abt schon gesagt hat kann man sich ja auf diese Angaben leider nicht verlassen 🙁 (Handles: 910, Threads: 28, GDI-Objekte: 41)

Wenns ein speicher Problem ist kann es gut sein das du die WPF Bindings nicht richtig implementiert hast.

Interessant, scheinbar erzeugt man ja an allen Ecken und Stellen in WPF irgendwelche Memory Leaks. Bindings nutze ich aber nicht. Ich habe nur zwei Image-Steuerelemente, die abwechselnd mit neuen Bildern beladen werden und bei dem das vordere Image immer ein- bzw. ausgeblendet wird.

Noch mal eine grundlegende Frage: Müsste sich bei einem Memory-, Handle- oder GDI-Leak nicht eine der Zahlen auch im ungenauen Taskmanager in der Prozess-Ansicht im laufe der Zeit aufblähen? Die verändern sich halt überhaupt nicht. ist der Taskmanager bei .NET-Prozessen nicht nur ein "Schätzeisen" sondern vollkommen komplett nutzlos? Nur damit ich weiß, welches Ausmaß das hat.

F
10.010 Beiträge seit 2004
vor 7 Jahren

Interessant, scheinbar erzeugt man ja an allen Ecken und Stellen in WPF irgendwelche Memory Leaks. Bindings nutze ich aber nicht. Ich habe nur zwei Image-Steuerelemente, die abwechselnd mit neuen Bildern beladen werden und bei dem das vordere Image immer ein- bzw. ausgeblendet wird.

Und du hast die bilder auch disposed?

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Und du hast die bilder auch disposed?

Nein, ich weiß leider nicht, wie ich das tun sollte. BitmapImage stellt keine Dispose-Methode bereit. Und das Image-Steuerelement stellt auch nichts bereit, womit das möglich wäre.

S
248 Beiträge seit 2008
vor 7 Jahren

Hallo PoWl,

könntest du bitte den Code der Methode "P_Slideshow_Vorabversion.MainWindow.<ImageChangeTimer_Tick>d__24.MoveNext()" posten. Vielleicht kommen wir damit weiter.

Danke

spooky

U
1.688 Beiträge seit 2007
vor 7 Jahren

Was bisher hier nicht beachtet wurde ist der "Console.WriteLine" Aufruf im Callstack.

Davon wurde hier berichtet:
http://stackoverflow.com/questions/27164538/console-writeline-throws-not-enough-storage-is-available-to-process-this-comman

Leider ohne Lösung. Evtl. ist der dort verlinkte Artikel hilfreich.

Oder der
Not enough storage is available to process this command

Falls hilfreich, solltest Du hier Deine Lösung posten.

Ohne Code lässt sich kaum noch etwas dazu sagen.

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Sehr gerne. Das hier ist der Code der Timer-Tick Routine, so wie er vor ein paar Tagen zum Zeitpunkt des Auftretens des Fehlers aussah:


        async private void ImageChangeTimer_Tick(object sender, EventArgs e)
        {
            Random rnd = new Random();

            lock (locker)
            {
                nextimage:
                do
                {
                    currentImageFile = rnd.Next(0, imageFiles.Count);
                    if ((history.Contains(currentImageFile)))
                        Console.WriteLine("douh! " + currentImageFile);
                }
                while (history.Contains(currentImageFile));
                history.Enqueue(currentImageFile);

                Console.WriteLine(currentImageFile);

                currentImageElement++;
                if (currentImageElement > 1)
                    currentImageElement = 0;

                try
                {
                    // Achtung, das hier wurde mittlerweile durch obengenannten Code geändert!
                    imageElements[currentImageElement].Source = new BitmapImage(new Uri(System.IO.Path.Combine(mediaDir, imageFiles[currentImageFile])));
                }
                catch (FileNotFoundException)
                {
                    log("Error! File not Found: " + imageElements[currentImageElement]);
                    imageFiles.RemoveAt(currentImageElement);
                    history.Clear();
                    goto nextimage;
                }
            }

            await Task.Delay(500); // Animation flüssiger machen

            if (currentImageElement == 1)
                sbFadeIn.Begin(Image2);
            else
                sbFadeOut.Begin(Image2);
        }

Darüberhinaus macht mein Programm nichts. Es ist der einzige Timer der läuft. Andere Programmteile werden nicht aufgerufen. Ich konnte bisher leider den Fehler nicht reproduzieren. Das Programm läuft gerade auf allen 3 Tablets seit 15h durch. Ich lass es mal weiter laufen.

Mittlerweile logge ich auch alle Exceptions mit. Im Internet fand ich, dass AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException; ausnahmslos alles einfängt, was an Exceptions geworfen wird.

        private void CurrentDomain_FirstChanceException(object sender, System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e)
        {
            Exception ex = e.Exception;
            log("FirstChanceException: " + ex.ToString());

            while (ex.InnerException != null)
            {
                ex = ex.InnerException;
                log("InnerException: " + ex.ToString());
            }
        }
F
10.010 Beiträge seit 2004
vor 7 Jahren

Bedenke auch das eine OutOufMemory durchaus durch ein "kaputtes" Image entstehen kann.

Ist bei GDI ein beliebtes problem.

5.657 Beiträge seit 2006
vor 7 Jahren

Hier ist eigentlich alles gesagt, was man dazu wissen muß: How to free the memory after the BitmapImage is no longer needed?

Nichts für Ungut, ich schätze die Mühe, die du dir machst, um mir zu helfen, danke dafür! Jedoch habe ich das Gefühl, bei der Resourcengeschichte jage ich einem Gespenst hinterher. Noch dazu finde ich im Internet keine Referenz darüber, dass es nicht legitim sei, ein WPF Image-Steuerelement einfach direkt mit einem BitmapImage zu beladen. 😉

Wie herablassend das rüberkommt, merkste sicher selbst. Die Exception, wegen der du dich ans Forum gewandt hast, ist doch sehr eindeutig. Wenn du den Vorschlägen des Forums nicht nachkommen willst, mußt du es ja nicht machen. Aber solche Statements sind einfach völlig kontraproduktiv.

Den Tip mit dem Memory-Profiler hast du auch ignoriert. Da kann man dir eben nicht helfen.

Weeks of programming can save you hours of planning

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

@FZelle
Der Medien-Ordner beinhaltet 40 Bilder, alle so ca. 2-3Mb groß. Die Bilddateien dürften in Ordnung sein, jedes einzelne Bild wurde nun schon etliche Male erfolgreich geladen.

@ujr
Das ist ja interessant! Ob das wohl auch systemabhängig ist? Immerhin lasse ich die Software auf schwachbrüstigen Windows-Tablets laufen, die sich sowieso etwas buggy verhalten. Allerdings ist ja hier klar von "Not enough storage is available to process this command". Bei mir ist es "Not enough quota...". Ich beziehe das mal in meine Untersuchung mit ein

@MrSparkle
(Pardon, wie gesagt hatte ich mich da etwas missverständlich ausgedrückt. Nochmals zur Erklärung: Ich als .Net-Neuling bin nur irritiert über den Umstand, dass sich etwaige Leaks, scheinbar überhaupt nicht äußerlich bemerkbar machen, dass ein Memory- oder Handle-Leak nicht in einem kontinuierlichen Anstieg der Gesamtauslastung dieser jenen Ressource führt, die sich im Taskmanager zwar nicht unter dem entsprechenden Prozess, jedoch aber in der Gesamtübersicht bemerkbar machen müsste. Das ist für mich ein Widerspruch. Sofern der Taskmanager überhaupt etwas zu gebrauchen sein soll muss er ja die Zahl dieser im gesamten System verbrauchten Ressourcen irgendwie korrekt anzeigen, was Abt ja auch bestätigt hat. Wenn ich alle 3 Sekunden ein 3Mb-Bild lade und dieses nicht wieder freigegeben würde müsste mein gesamter Arbeitsspeicher innerhalb von 5 Minuten voll sein. Auch müsste die Anzahl im System verwendeter Handles (sofern diese beim Laden eines Bildes nicht freigegeben werden) um 1200 Handles pro Stunde steigen. Auf einem System, welches nur 1Gb RAM und im Schnitt 23000 dauerhaft vergebene Handles hat macht sich ein solcher Anstieg innerhalb kürzester Zeit bemerkbar. Ich konnte wie gesagt nichts davon beobachten. Insofern ist es für mich, mangels besseren Verständnis, eben für mich fraglich, ob hier denn überhaupt ein Leak vorliegt. Gibt es verschiedene Arten von Handles? Nach wie vor ist es verwunderlich, welchen Sinn die Möglichkeit, das BitmapImage per UriSource-Property zu beladen, haben soll, wenn es doch sowieso zu einem Leak führt. (Außer es handelt sich um einen .Net Bug).

Den Code aus dem Link, den du eben genannt hast, habe ich ja bereits (wie oben aufgezeigt) übernommen. Ich lasse mein Programm derzeit damit laufen um zu schauen, ob der Fehler damit immer noch auftritt.

Zum Profiler: Den Tipp habe ich keineswegs ignoriert. Ich bin nur gerade noch dabei, verschiedene Profiler auszuprobieren und versuche diese auf mein Problem anzusetzen. Ich muss erst mal lernen, wie man diese Programme überhaupt benutzt und auf welche Weise sie mir nützliche Informationen liefern. Aus Höflichkeit und da ich der Bittsteller bin, hielt ich es für angemessen, eine geringe Reaktionszeit zu bewahren und im Thread auch zwischendurch etwaige Rückfragen zu beantworten.

Ich klinke mich besser erst mal aus und melde mich zurück, sobald ich das Programm mit einem Profiler untersucht habe. bzw. die Exception erneut auftritt. 🙂

S
248 Beiträge seit 2008
vor 7 Jahren

Hallo,

warum schreibst du in einer WPF-Anwendung in die Konsole? Hast du diese umgeleitet in eine Datei oder manuell eine Konsole geöffnet?

Entferne die Console.WriteLine(..) Aufrufe (die ja den Fehler auslösen) und schau ob das Programm dann korrekt funktioniert.
Dann kannst du auch den Handle "Leak" ausschließen.

Grüße
spooky

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Die Konsolenausgabe nutze ich, um Statusausgaben zu machen, die ich während der Entwicklung meines Programms nutze, um dessen Verhalten zu beobachten. Richtig brauchen tu ich sie nicht.

Ich habe mich nun mal ans profiling gemacht und erst mal den internen Profiler von Visual Studio genutzt (warum auch nicht 😄).

Alte Methode


var bitmap = new BitmapImage(new Uri(System.IO.Path.Combine(mediaDir, imageFiles[currentImageFile])));
imageElements[currentImageElement].Source = bitmap;

Hier habe ich in der Tat ein Leak feststellen können. Allerdings ein viel kleineres als ich bisher erwartete. Die Anzahl an Objekten steigt permanent. Seltsamerweise nicht in der gleichen Geschwindigkeit, wie ich die Bilder wechsle. Es werden hier auch nicht die gesamten Bilddaten im RAM behalten sondern nur einige kBytes. Das meiste sind Uri und WeakReference.
Kann jemand nachvollziehen, warum .Net das macht? Wie ich ja bereits erörtert habe, ergibt es für mich keinen Sinn, wieso BitmapImage die Möglichkeit bereitstellt, ihm eine UriSource zu übergeben, wenn man sich damit sowieso ein MemoryLeak erzeugt. Ist dieses Verhalten völlig klar und ich habe nur Tomaten auf den Augen oder ist das ein .Net-Bug, den man sogar mal melden sollte?
Sowohl bei den Objekttypen WeakReference als auch bei Uri ist es immer der Eintrag "Hashtable [Statische Variable ImagingCache._imageCache]", bei dem die Verweiszahl kontinuierlich steigt. Was ist das denn? Und warum wird das nicht freigegeben? Nachdem das Image-Steuerelement schon lange ein anderes Bild geladen hat dürfte doch überhaupt keine Referenz mehr auf irgend ein Überbleibsel eines ehemals geladenen Bildes bestehen und der GC müsste das einfach wegräumen. Nach meiner Vorstellung zumindest. Das ganze erstaunt mich auch ein wenig, im negativen Sinne. Habe ich hier einen Sonderfall erwischt oder muss man an jeder Stelle und Ecke in .NET aufpassen und irgendwelche besonderen Codeteile einbauen, damit man sich nicht ein Memory-Leak erzeugt? X(

Neue Methode


var bitmap = new BitmapImage();
using (var stream = File.OpenRead(System.IO.Path.Combine(mediaDir, imageFiles[currentImageFile])))
{
    bitmap.BeginInit();
    bitmap.CacheOption = BitmapCacheOption.OnLoad;
    bitmap.StreamSource = stream;
    bitmap.EndInit();
    bitmap.Freeze();
}

imageElements[currentImageElement].Source = bitmap;

Dieser Code läuft hingegen seit >500 Minuten (über Nacht laufen lassen) völlig rund. Durch das Ersetzen von UriSource mit StreamSource konnte ich die Leaks weitesgehend eindämmen.

Nundenn, ein Leck ist abgedichtet! 🙂 Danke soweit für die Hilfe!
Ob das das ursprüngliche Problem jedoch löst ist ungewiss. Ich werde sehen, ob bzw. wann die Exception wieder auftritt.

Hinweis von MrSparkle vor 7 Jahren

Bitte keine externen Filehoster verwenden, sondern Bilder als Dateianhang hochladen.

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

MrSparkle, daher habe ich die Bilder extra auf meinen privaten Webspace geladen, wo ich sichergehen kann, dass sie auch in 10 Jahren noch online sind 😉 Aber ich verstehe.

Hier noch der Screenshot der alten Methode:

709 Beiträge seit 2008
vor 7 Jahren

Die Konsolenausgabe nutze ich, um Statusausgaben zu machen, die ich während der Entwicklung meines Programms nutze, um dessen Verhalten zu beobachten.

Als Alternative bietet sich Debug.WriteLine & Co an.
Die Ausgaben werden dann im Output-Fenster von Visual Studio angezeigt.

D
985 Beiträge seit 2014
vor 7 Jahren

Die Klasse BitmapImage ist dokumentiert. Reinschauen lohnt sich (gerade auch zum Thema Caching).

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Ja richtig, aber auch in der Doku (https://msdn.microsoft.com/de-de/library/system.windows.media.imaging.bitmapimage%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396)

wird es wie folgt gemacht:

// Create the image element.
Image simpleImage = new Image();    
simpleImage.Width = 200;
simpleImage.Margin = new Thickness(5);

// Create source.
BitmapImage bi = new BitmapImage();
// BitmapImage.UriSource must be in a BeginInit/EndInit block.
bi.BeginInit();
bi.UriSource = new Uri(@"/sampleImages/cherries_larger.jpg",UriKind.RelativeOrAbsolute);
bi.EndInit();
// Set the image source.
simpleImage.Source = bi;

Das ist genau der Code, welcher bei mir zu einem Leak führt. 🤔

D
985 Beiträge seit 2014
vor 7 Jahren

Schon mal angeschaut, was BitmapImage.CacheOption bewirkt?

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Aber klar 🙂 Was das bewirkt kann man ja hier nachlesen:
BitmapCacheOption-Enumeration

Jedoch kann ich mir keinen Reim darauf machen, warum das Caching dafür verantwortlich sein soll, dass ein Memory-Leak entsteht.

v.a. weil "Caches the entire image into memory. This is the default value." die Default-Einstellung ist. Was spricht dagegen, das Bild im Arbeitsspeicher zu cachen? Warum sammeln sich Uri-Objekte an, obwohl diese schon längst nicht mehr benötigt werden? Das lässt die Dokumentation offen.

16.806 Beiträge seit 2008
vor 7 Jahren

Das Leak ist in meinen Augen immer noch das gewesen, dass Du die Streams nie geschlossen hattest.
Da Du nun die Uri verwendest, öffnest Du keinen Stream mehr, den Du selbst schließen musst.
=> behoben.

Ein anderes potentielles Leak hab ich persönlich nie gesehen und seh jetzt auch kein weiteres.

In der Tat scheint übrigens Dein Console.Writeline für die Exception verantwortlich zu sein; das System.IO.__ConsoleStream.Write ist mir im StackTrace irgendwie nicht aufgefallen.

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Das Leak ist in meinen Augen immer noch das gewesen, dass Du die Streams nie geschlossen hattest.
Da Du nun die Uri verwendest, öffnest Du keinen Stream mehr, den Du selbst schließen musst.
=> behoben.

Moment mal 😁 Es war genau andersrum. Ich verwendete am Anfang die Uri und diese hatte ein Leak. Später habe ich die Variante mit dem Stream übernommen (der per using auch geschlossen wurde), diese Variante hatte kein Leak. Eine Variante, in der ein Stream erzeugt, aber nie geschlossen wurde, gab es nie. Deshalb wundere ich mich ja so, warum die Uri-Variante denn ein Leak erzeugt, sollte sie doch seitens .Net so beschaffen sein, dass sie das nicht tut, da der Programmierer bei deren Verwendung die Verantwortung über das ordnungsgemäße Schließen der Ressourcen an diese komplett abgibt.

In der Tat scheint übrigens Dein Console.Writeline für die Exception verantwortlich zu sein; das System.IO.__ConsoleStream.Write ist mir im StackTrace irgendwie nicht aufgefallen.

Das ist ja echt abgefahren. 🤔

1.040 Beiträge seit 2007
vor 7 Jahren

Also wenn man einfach die Fehlermeldung googelt, dann ist fast überall davon zu lesen, dass die Auslagerungsdatei vollläuft bzw. die Größe eben dieser angepasst werden sollte.
TechNet - Not enough quota is available to process this command.

Und ja, Console.Writeline löst den Fehler aus, ist ja klar im StackTrace zu sehen. =)

PoWl, wenn du die Möglichkeit hast, dann deinstalliere das deutsche Sprachpaket - mit englischen Fehlermeldungen kommt man viel, viel weiter.

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Also wenn man einfach die Fehlermeldung googelt, dann ist fast überall davon zu lesen, dass die Auslagerungsdatei vollläuft bzw. die Größe eben dieser angepasst werden sollte.

>

Verständlicherweise hast du nicht den ganzen Thread gelesen aber: Das kann praktisch nicht die Ursache gewesen sein. Zum Zeitpunkt des Vorfalls war noch mehr als 1Gb Festplattenspeicher übrig und der RAM nur zu 60% ausgelastet.

War wohl ein Bug 🤔

1.040 Beiträge seit 2007
vor 7 Jahren

Doch, habe den ganzen Thread gelesen. =)

Die Auslagerungsdatei wird auch verwendet, wenn der RAM nicht vollständig belegt ist.
Zudem kann ihr eine Größe zugewiesen werden. Anderenfalls wird die Größe vom System bestimmt - wobei in dem Falle wahrscheinlich nicht der gesamte, restliche Festplattenplatz genutzt wird.
Also kann es sehr wohl die Ursache gewesen sein.

Schaue doch mal nach, wie die Größe für die Datei eingestellt ist. Google weiß sicher, wo du es bei dem genutzten Betriebssystem findet. =)

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Ah! Ja das dachte ich mir schon, dass die Auslagerungsdatei schon während des Betriebs genutzt wird. Gemäß diesem elegant designten Einstelldiaglogfenster hier ist die jedoch auf 1792MB Größe begrenzt. Das ist mehr, als auf der Festplatte ohnehin noch frei ist, das sollte ausreichen. Der Physische Arbeitsspeicher ist laut Ressourcenmanager soweit belegt, dass noch dauerhaft 200MB frei sind.

Ich habe den Fesplattenspeicher auch mal auf 20MB reduziert, um den Fehler weiterhin zu provozieren. Bisher ist der leider nicht einmal mehr aufgetreten.

1.040 Beiträge seit 2007
vor 7 Jahren

Hast du das Console.Writeline denn wieder reingenommen? =)

P
PoWl Themenstarter:in
219 Beiträge seit 2008
vor 7 Jahren

Ich habe es bisher gar nicht rausgenommen 😁 Derzeit entwickle ich die Software ja noch und ich finde es durchaus interessant, zu beobachten, ob oder wann der Fehler wieder auftritt bzw. möchte ja auch meine Statusausgaben auf dem Zielsystem sehen. Später, wenn die Anwendung dann einfach nur noch laufen soll, werde ich die Konsole abschalten.

P
19 Beiträge seit 2016
vor 7 Jahren

Wenn ich das richtig verstanden habe, wird bei deaktiviertem Cache & URI der Stream offen gelassen.
Bei Aktivierten Cache wird die Datei in den Arbeitsspeicher geladen & der Stream wieder geschlossen, hierbei gibt es die Optionen 'OnDemand & OnLoad' deren namen für sich selbst sprechen.