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

  • »
  • Portal
  • |
  • Mitglieder
Beiträge von PoWl
Thema: Daten für Playlist-Verwaltung wie am besten (zwischen)speichern?
Am im Forum: Datentechnologien

Alles klar. Danke für die Antworten!

Ich denke ich werde mich dann mal mit SQlite beschäftigen, das scheint genau das zu sein, was ich brauche :-)

Eine eigene API möchte ich nicht schreiben, das Tool selbst wird schon genug Arbeitsaufwand mit sich bringen, da muss das Drum-Rum einfach sitzen sonst steh ich am Ende ganz ohne Ergebnis da, man kennt das.

Thema: Daten für Playlist-Verwaltung wie am besten (zwischen)speichern?
Am im Forum: Datentechnologien

Zitat von Abt
Ich fürchte, dass Performance hier nicht Dein ausschlaggebendes Kriterium sein wird.
Eine Serialisierung zB. von Json in Dateien wird erst bei einer dreistelligen MB-Größe in Sachen Performance bei solchen Anwendungen/kleinen Tools relevant.

Dass ich das wahrscheinlich nicht mal merke wenn ich da mal meine 1MB Daten kurz auf meine SSD schreibe habe ich mir schon gedacht. Aber das passiert dann halt quasi jedes mal, wenn ich auch nur irgend eine Aktion mit einem Musik-Titel ausführe, und wenn es nur ist, z.B. eine Checkbox anzuklicken um den Titel irgendwie für irgendetwas zu markieren. Das erscheint mir doch irgendwie amateurhaft. Also dann wohl eher Datenbank.

Zitat von Abt
Access eignet sich dafür nie. NIE NIE NIE NIE. NICHTS spricht für Access. NICHTS.
Ja, SQlite schon eher.

Aber ist MS Access nicht genau für solche Zwecke da? Eine relationale Datenbank in Form einer einzigen Datei lokal auf dem Rechner vorzuhalten und darüberhinaus in Form der Software "Microsoft Access" noch ein komfortables Userinterface zur Verwaltung dieser Datenbank bereitzustellen? Oder muss hierfür Access immer auch auf dem Rechner installiert sein und mein Programm ist hier auf externe Programm-Logik angeweisen?

SQlite ist ja dann quasi das gleiche. Hier halte ich natürlich auf jeden Fall die ganze SQlite-Logik in meiner Software vor und kann mit externen Tools meine Datenbankdatei laden und anschauen.

Gibt es sonst noch etwas zu beachten?

Zitat von T-Virus
Wenn du ganz sicher gehen willst, dass deine DB nicht durch einen Schreibvorgang bei einem Stromausfall beschädigt wird, kannst du auch regelmäig Backups durch einfaches Kopieren der DB anfertigen.

Guter Punkt. Das würde in jedem Fall helfen.

Thema: Daten für Playlist-Verwaltung wie am besten (zwischen)speichern?
Am im Forum: Datentechnologien

Hi,

ich würde gerne eine Playlistverwaltung in C# schreiben, welcher über eine API mit einem Musikstreamingdienst in Verbindung steht und dort z.B. automatisch neue Releases von Künstlern in spezifische lokal im Programm gespeicherte Playlists einsortiert.

Diese Playlists muss ich nun natürlich in Form von Tabellen in meiner Software abbilden. Im einfachsten Fall würde ich hier einfach Klassen und Listen verwenden. Jedoch muss ich sicherstellen, dass nicht nur nach Beendigung der Software der aktuelle Programmzustand lokal auf dem Rechner zwischengespeichert wird sondern auch zwischendurch immer mal wieder, falls es zum Absturz der Software oder des Computers kommt, ohne dass zuvor gespeichert wurde.

Je nach Nutzungsgrad der Software stelle ich es mir nicht gerade performant vor, nach jedem Arbeitsschritt die gesamten Datenobjekte zu serialisieren und in eine Datei reinzuspeichern. Abgesehen davon, was wohl passiert, wenn während des Schreibvorgangs der PC mal abstürzt und damit die Datei hinüber ist. D.h. ich möchte also dass der aktuelle Programmzustand permanent live mit einer Art Datenbank synchronisiert wird so dass ich nach einem Softwareabsturz einfach alles wieder laden kann und genau da weitermachen kann, wo ich zuvor aufgehört hatte. Idealerweise würde hierbei die Synchronisation mit meinen Datenobjekten völlig automatisch funktionieren oder ich würde innerhalb meines Programms einfach direkt mit der Datenbank kommunizieren (ohne dass alle Daten in Form von Objekten permanent im RAM vorgehalten werden)

Welche Technik/Strategie eigent sich hierfür? Auf eine getrennt zu installierenden Datenbankserver bzw. generell Zusatzsoftware würde ich gerne verzichten. Empfiehlt sich vielleicht sogar eine Access-Datenbank? Oder so etwas wie SQlite? Bei der Fülle an Möglichkeiten fehlt mir irgendwie der Überblick Wünschenswert wäre am Ende auch ein Format, das es zulässt, die Daten hinterher noch mit externer Software darstellen/bearbeiten zu können, was z.B. für XML oder eine Access-Datenbank sprechen würde.

lg Paul

Thema: Soundschema ändern oder deaktivieren
Am im Forum: Grafik und Sound

Hi,

der ursprungs-thread ist ja nun schon etwas alt, aber das Thema interessiert mich auch, da ich ein kleines recording-tool für den Stereomix coden möchte, für das es sinnvoll wär, temporär alle stör-Sounds deaktivieren zu können.

Hat jemand eine Idee, wonach ich da suchen kann, um auf eine Lösung zu kommen?

lg

Thema: Touchscreen deaktivieren wenn Bildschirm aus
Am im Forum: Rund um die Programmierung

Hi,

ich habe hier ein kleines Windows Tablet, welches ich gerne als Fernsteuerung für diverse Bastelanwendungen verwenden würde, z.B. Lichtsteuerung. Da läuft dann ein selbstgeschriebenes Fullscreen-GUI Programm, welches ich z.B. in WPF/C# schreibe, welches dann über Bluetooth oder WLAN mit der Hardware kommuniziert. Damit das Programm jederzeit reagieren kann darf das Tablet währenddessen nicht in einen Energiesparmodus gehen, daher habe ich den Connected Standby (Instantgo) deaktiviert und Windows so konfiguriert, dass es beim Drücken des Ein/Aus-Schalters lediglich der Bildschirm ausgeschaltet wird. Das funktioniert auch so weit.

Allerdings ist der Touchscreen des Tablets weiterhin aktiv und jede Berührung führt dazu, dass der Bildschirm, wie bei einer Mausbewegung, automatisch wieder an geht.

Wie kann ich das verhindern? Ich muss quasi den Touchscreen deaktivieren, sobald der Bildschirm ausgeschaltet wird und ihn wieder aktivieren, sobald der Bildschirm angeschaltet wird.

Geht das irgendwie durch eine Einstellung im Betriebsystem oder muss ich hier quasi ein kleines Tool im Hintergrund laufen lassen, welches den Betriebszustand des Bildschirms überwacht und den Touchscreen passend ein- und ausschaltet? (Wie auch immer man das realisieren kann)

Eine Möglichkeit, den Touchscreen zu deaktivieren bestünde z.B. darin, das zugehörige Gerät zu deaktivieren. Das wiederum ginge wohl ganz einfach mit dem Commandline-tool devcon.exe (Windows Device Console), was mir aber als eine nicht allzu überaus elegante Methode erscheint.

lg Paul

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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.

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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.

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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.

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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.

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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.

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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.

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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.

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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:

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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.

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

@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.

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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());
            }
        }

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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?

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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.

Zitat
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?
Zitat
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?

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

;(

Na gut, back to topic:

Zitat
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:
Zitat
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.
Zitat
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.
Zitat
[...] 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:
Zitat von 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:
Zitat von Abt
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
Zitat
There was a bug in Wpf that we were bitten by where BitmapImage objects are not released unless you freeze them. http://blogs.msdn.com/b/jgoldb/archive/2008/02/04/finding-memory-leaks-in-wpf-based-applications.aspx 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.

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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.

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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.

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

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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()?

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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.

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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.

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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?

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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

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

Thema: Nicht genügend Quoten, um den angeforderten Dienst auszuführen bei Dauerbetrieb
Am im Forum: GUI: WPF und XAML

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:

Fehler
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?