Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 9.972

beantworten | zitieren | melden

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

Ist bei GDI ein beliebtes problem.
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5.655
Herkunft: Leipzig

beantworten | zitieren | melden

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

Zitat von PoWl
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
private Nachricht | Beiträge des Benutzers
PoWl
myCSharp.de - Member



Dabei seit:
Beiträge: 219

Themenstarter:

beantworten | zitieren | melden

@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.
Dieser Beitrag wurde 17 mal editiert, zum letzten Mal von PoWl am .
private Nachricht | Beiträge des Benutzers
Spook
myCSharp.de - Member



Dabei seit:
Beiträge: 244
Herkunft: Esslingen a.N.

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
PoWl
myCSharp.de - Member



Dabei seit:
Beiträge: 219

Themenstarter:

beantworten | zitieren | melden

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 :D).

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.
Dieser Beitrag wurde 7 mal editiert, zum letzten Mal von PoWl am .
Attachments

Moderationshinweis von MrSparkle (21.12.2016 - 13:16)

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

private Nachricht | Beiträge des Benutzers
PoWl
myCSharp.de - Member



Dabei seit:
Beiträge: 219

Themenstarter:

beantworten | zitieren | melden

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:
Attachments
private Nachricht | Beiträge des Benutzers
pinki
myCSharp.de - Member

Avatar #avatar-4072.jpg


Dabei seit:
Beiträge: 702
Herkunft: OWL

beantworten | zitieren | melden

Zitat von PoWl
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.
private Nachricht | Beiträge des Benutzers
Deaktiviertes Profil
myCSharp.de - Member



Dabei seit:
Beiträge: 985

beantworten | zitieren | melden

Die Klasse BitmapImage ist dokumentiert. Reinschauen lohnt sich (gerade auch zum Thema Caching).
private Nachricht | Beiträge des Benutzers
PoWl
myCSharp.de - Member



Dabei seit:
Beiträge: 219

Themenstarter:

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
Deaktiviertes Profil
myCSharp.de - Member



Dabei seit:
Beiträge: 985

beantworten | zitieren | melden

Schon mal angeschaut, was BitmapImage.CacheOption bewirkt?
private Nachricht | Beiträge des Benutzers
PoWl
myCSharp.de - Member



Dabei seit:
Beiträge: 219

Themenstarter:

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.761

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
PoWl
myCSharp.de - Member



Dabei seit:
Beiträge: 219

Themenstarter:

beantworten | zitieren | melden

Zitat von Abt
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.
Zitat von Abt
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.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von PoWl am .
private Nachricht | Beiträge des Benutzers
p!lle
myCSharp.de - Member

Avatar #avatar-3556.jpg


Dabei seit:
Beiträge: 1.040

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
PoWl
myCSharp.de - Member



Dabei seit:
Beiträge: 219

Themenstarter:

beantworten | zitieren | melden

Zitat von p!lle
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.

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
private Nachricht | Beiträge des Benutzers
p!lle
myCSharp.de - Member

Avatar #avatar-3556.jpg


Dabei seit:
Beiträge: 1.040

beantworten | zitieren | melden

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. =)
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von p!lle am .
private Nachricht | Beiträge des Benutzers
PoWl
myCSharp.de - Member



Dabei seit:
Beiträge: 219

Themenstarter:

beantworten | zitieren | melden

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.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von PoWl am .
Attachments
private Nachricht | Beiträge des Benutzers
p!lle
myCSharp.de - Member

Avatar #avatar-3556.jpg


Dabei seit:
Beiträge: 1.040

beantworten | zitieren | melden

Hast du das Console.Writeline denn wieder reingenommen? =)
private Nachricht | Beiträge des Benutzers
PoWl
myCSharp.de - Member



Dabei seit:
Beiträge: 219

Themenstarter:

beantworten | zitieren | melden

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.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von PoWl am .
private Nachricht | Beiträge des Benutzers
PottKafe
myCSharp.de - Member



Dabei seit:
Beiträge: 19
Herkunft: NRW

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
PoWl
myCSharp.de - Member



Dabei seit:
Beiträge: 219

Themenstarter:

beantworten | zitieren | melden

Zitat von PottKafe
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.

Hm, aber was für einen Sinn ergibt das? Immerhin kann man von außen gar nicht auf den Stream zugreifen, um ihn zu schließen. Zudem scheint die Anzahl der verwaisten Objekte nicht mit der Anzahl der bisher angezeigten Bilder übereinzustimmen. Im Screenshot des Profilers mit dem Leak verwaisen innerhalb von ca. 2332 Sekunden 225 Uri-Objekte und 253 WeakReference-Objekte. Jedoch wurden in dieser Zeit auch 777 Bilder angezeigt. Im Beispielcode von MSDN wird es ja auch so gemacht, dass dem BitmapImage einfach nur eine UriSource zugeteilt wird. Ob die MSDN-Ersteller wirklich ein Leak in Kauf nehmen?

Woher hast du die Info, dass der Stream offen gelassen wird? Im Code geguckt? Das schaue ich mir auch mal an.
private Nachricht | Beiträge des Benutzers
PottKafe
myCSharp.de - Member



Dabei seit:
Beiträge: 19
Herkunft: NRW

beantworten | zitieren | melden

BitmapCacheOption Enumeration

Auf englisch versteht man es ein wenig besser.
None
Do not create a memory store. All requests for the image are filled directly by the image file.

Bereitgestellt wird die Bitmap durch die klasse 'BitmapDownload'

Hier wird der Stream geöffnet doch nie geschlossen. Ob von anderer stelle irgendwann der Stream geschlossen wird konnte ich nicht erkennen.
private Nachricht | Beiträge des Benutzers
Deaktiviertes Profil
myCSharp.de - Member



Dabei seit:
Beiträge: 985

beantworten | zitieren | melden

Der tiefere Sinn ist der, das das Laden von Bitmaps zeitintensiv sein kann, vor allem, wenn die Bilder aus dem Internet geladen werden. Über die Cache-Optionen kann man einstellen, wie man es denn gerne hätte.

Wenn der Cache aktiv ist dann werden die im Cache über die Uri als Schlüssel gehalten und eventuell irgendwann mal da auch wieder herausgeräumt (wann auch immer). Ein Cache ist ja deswegen ein Cache weil er dort etwas so lange wie möglich vorhält und nicht weil er das so schnell wie möglich wieder vergisst.

Handelt es sich auch um 777 unterschiedliche Bilder? Dann weisen die 225 Uri-Instanzen doch eindeutig darauf hin, dass der Cache auch aufgeräumt wird.
private Nachricht | Beiträge des Benutzers
PoWl
myCSharp.de - Member



Dabei seit:
Beiträge: 219

Themenstarter:

beantworten | zitieren | melden

Gut, das wiederum macht Sinn. Es ist ja auch nicht zwangsläufig immer vorgesehen, dass ein Programm unendlich lange geöffnet bleibt und immer neue Bilder läd.

Es waren übrigens nur 44 unterschiedliche Bilddateien, da passen die 255 Objekte nicht dazu.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.761

beantworten | zitieren | melden

Dir ist schon klar, dass im Hintergrund immer mehr Objekte erzeugt werden, als Du es als Entwickler siehst?
Nen Profiler bekommt auch mit, wenn das .NET Framework Objekte erzeugt...
private Nachricht | Beiträge des Benutzers