RAM Speicher Verwaltung

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 21 Antworten in diesem Thema. Der letzte Beitrag () ist von n1nja.

    RAM Speicher Verwaltung

    Hallo Leute,

    ich bin bastel mir gerade ein "kleines" Projekt um den Zwischenspeicher zu verwalten.

    Das Tool soll mir alle Clipboards abspeichern sodass ich später wieder darauf zugreifen kann.
    Auch falls diese Dateien gelöscht wurden. Ich speicher also die Bytes ab, die in der Zwischenablage waren.
    Das war aber extrem nervig, da sich in wenigen MInuten/Stunden viel Daten angesammelt hatten.

    Jetzt speicher ich die Dateien nur noch ab, falls diese gelöscht wurden.

    Daraufhin hatte ich noch ein Problem, zwecks der Speicherverwaltung.
    Erste hatte ich eine Klasse mit Clipboards die in einer Liste gespeichert wurden...
    Zurzeit arbeite ich pro Clipboard mit Serialisierung und speicher es direkt als Datei ab.

    Funktioniert schon deutlich besser.

    Jedoch wenn ich mal über 2-3GB kopiere, krieg ich eine Fehlermeldung "OutOfMemory".

    Überlegt habe ich mir pro Clipboard eine Datei zu erstellen die serialisiert wurde.
    Jedoch bringt mir das nicht viel wenn im Zwischenspeicher 30 x 100MB Files sind.


    Wie regelt man so große Zwischenspeichermengen?!

    Komm ich da überhaupt drum rum pro Datei eine extra Datei zu erstellen?
    Das wäre noch die sinnvollste Idee, die ich hätte.

    Vllt. hat ja hier einer noch ne weitere Idee, wie man das am besten anstellen kann.

    Edit:
    hier mal noch die 2 Klassen die ich abspeichere

    Clipboard
    Spoiler anzeigen

    C#-Quellcode

    1. namespace ClipBoardManager.Core
    2. {
    3. [Serializable]
    4. public class ClipboardObj
    5. {
    6. public ClipboardObj()
    7. {
    8. }
    9. [Serializable]
    10. public enum ClipboardType
    11. {
    12. Text,
    13. Bitmap,
    14. Filedrop,
    15. Audio
    16. }
    17. public string Time { set; get; }
    18. public ClipboardType Type { set; get; }
    19. public object Value { set; get; }
    20. public static ClipboardObj GetClipboardObjectFromList(string Time)
    21. {
    22. ClipboardObj clip = null;
    23. foreach (var c in AppData.ClipboardObjectList)
    24. {
    25. if (c.Time == Time)
    26. {
    27. clip = c;
    28. break;
    29. }
    30. }
    31. return clip;
    32. }
    33. }
    34. }



    Filedrop
    Spoiler anzeigen

    C#-Quellcode

    1. namespace ClipBoardManager.Core
    2. {
    3. [Serializable]
    4. public class Filedrops
    5. {
    6. public Filedrops(ClipboardObj Clipboard)
    7. {
    8. _clipboard = Clipboard;
    9. }
    10. private ClipboardObj _clipboard;
    11. public ClipboardObj Clipboard { set { _clipboard = value; } get { return _clipboard; } }
    12. public Dictionary<string, byte[]> FileValues { set; get; } = new Dictionary<string, byte[]>();
    13. public static Filedrops GetFiledropFromList(ClipboardObj Clipboard)
    14. {
    15. Filedrops filed = null;
    16. foreach (var file in AppData.FiledropList)
    17. {
    18. if (file.Clipboard == Clipboard)
    19. {
    20. filed = file;
    21. break;
    22. }
    23. }
    24. return filed;
    25. }
    26. }
    27. }




    Vielen dank im Voraus.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „n1nja“ ()

    Die Files muss ich ja trotzdem erstmal im Tool haben um sie zu verwalten. Danach werden sie in einen Programmordner kopiert, soweit ist das schon richtig.

    Aber irgendwie muss es ja eine Lösung geben für größere Mengen:)

    n1nja schrieb:

    Änderungsdatum, Größe, Datentyp usw.
    Mit der FileInfo Klasse geht das wunderbar.

    n1nja schrieb:

    Dann die Verschlüsselung an sich selbst und das zippen.
    Dann solltest du dich mal mit Streams befassen:



    Das wurde mit folgendem Code erzielt:

    C#-Quellcode

    1. using (FileStream fsOldFile = new FileStream("oldBigFile.txt", FileMode.Truncate, FileAccess.ReadWrite))
    2. using (FileStream fsNewFile = new FileStream("newBigFile.txt", FileMode.Truncate, FileAccess.ReadWrite))
    3. using (FileStream fsZip = new FileStream("ZippedFile.txt", FileMode.Truncate, FileAccess.ReadWrite))
    4. using (GZipStream gzsZip = new GZipStream(fsZip, CompressionMode.Compress))
    5. using (GZipStream gzsUnzip = new GZipStream(fsZip, CompressionMode.Decompress))
    6. {
    7. Random r = new Random();
    8. byte[] buffer = new byte[20000];
    9. Console.WriteLine("Creating 2GB of data"); //Also Festplattenhersteller GB
    10. for (int j = 0; j < 100000; j++)
    11. {
    12. r.NextBytes(buffer);
    13. fsOldFile.Write(buffer, 0, buffer.Length);
    14. }
    15. fsOldFile.Position = 0;
    16. Console.WriteLine("zipping 2GB of data");
    17. while (fsOldFile.Read(buffer, 0, buffer.Length) == buffer.Length)
    18. {
    19. gzsZip.Write(buffer, 0, buffer.Length);
    20. }
    21. fsZip.Position = 0;
    22. Console.WriteLine("unzipping 2GB of data");
    23. while (gzsUnzip.Read(buffer, 0, buffer.Length) == buffer.Length)
    24. {
    25. fsNewFile.Write(buffer, 0, buffer.Length);
    26. }
    27. }

    Der leider crasht nachdem alles erledigt ist, da sich die Streams gegenseitig die BaseStreams wegdisposen.
    Wenn du nun noch nen CryptoStream nach den GZipStream nachschaltest, hast du was du willst.

    Warum aber wird bei mir mit der FileInfo Klasse die Klasse dann genauso groß?

    Und liest Filestream nicht auch in den RAM?
    Ich verwende zurzeit den MemoryStream.

    Dh. Mit dem Abändern vom Stream sollte mein Problem gelöst sein?

    Dann noch ne Frage? Wie kann ich dann mein Objekt, also die Klasse serialisieren ohne MemStream?

    n1nja schrieb:

    Warum aber wird bei mir mit der FileInfo Klasse die Klasse dann genauso groß?
    Ich weiß nicht, was du mit dieser FileInfo alles anstellst.

    n1nja schrieb:

    Und liest Filestream nicht auch in den RAM?
    Ich verwende zurzeit den MemoryStream.
    Der FileStream liest aus einer Datei oder schreibt in eine hinein. Mit dem RAM hat der erstmal nichts am hut.
    Der MemoryStream hingegen liest aus dem RAM oder schreibt in diesen Hinein. Wenn man die aufeinanderstöpselt, wird natürlich die Datei in Teilen oder komplett in den RAM geladen.

    Ich jedoch mache etwas anderes. Ich reserviere im RAM exakt 20.000 Bytes, die ich für alle Operationen benutze. Der Speicherverbrauch kann also nie über diese 20.000 Bytes hinauswachsen.

    n1nja schrieb:

    Wie kann ich dann mein Objekt, also die Klasse serialisieren
    Was willst du mit der Serialisiserung erreichen?
    Na nix. Ich les die Datei ein um die Infos zu holen.

    Und die Variable ist dann nicht exakt so groß. Aber trotzdem nicht normal im Vergleich zu anderen Datentypen.

    Bin grad nicht am PC, kanns leider nicht genau sagen.

    Und mit dem Serialisieren speicher ich alle Infos ab natürlich. Steht alles im ersten Post wie die Klassen aufgebaut werden.

    So kann ich easy mit einer Datei sämtlich Daten vom Tool abspeichern. Brauch keine INI Files usw.

    Könnte aber es direkt auch mal mit nen FileStream versuchen.

    Und wie wirkt sich das auf die Performance aus wenn ich eine Datei erstelle und dann mit nen Cryptostream bzw Zippe?
    Hab ich 3 ma einen Schreibvorgang, oder seh ich da was falsch?
    Ach, meinst du etwa die Length Property der FileInfo klasse?
    Ja die zeigt natürlich auf die Größe der Datei, und nicht der Variablen. FileInfo ist ja auch kein Array.

    Was die Serialisiserung angeht, könntest du dir mal protobuf-net von Marc Gravell ansehen. Das ist ein ziemlich kleines, vorallem aber außerordentlich schnelles Format. Kannste per NuGet einbinden, dekorierst deine Klassen mit den ProtoContract und ProtoMember Attributen, und schon kanns losgehen. Mit der Klasse Serializer kannst du, ohne großartig Einstellungen vornehmen zu müssen, Objekte direkt in bytes serialisiseren. Ich benutze es bspw. in einer App um Objekte, die zu einem Server geschickt werden müssen erstmal auf dem mobilen Gerät in einer SQLite Tabelle zwischenzuspeichern. Das können mitunter auch mehrere Bilder sein.
    Nee ich meine nicht die Length Proberty. Das is mir alles bewusst.

    Ich mein die Var direkt selbst. Wenn ich die speicher ist sie allein schon über 1mb. Was ungewöhnlich ist.

    Und ja genau deswegen benutze ich den BinaryFormatter, damit ich mich um nix kümmern muss wenn ich Daten speichern möchte. Mach das schon paar Jahre so bei größeren Projekten.

    Und weil man damit auch ziemlich gut viele Sachen aufeinmal speichern kann.

    Aber gut, ich werd mir das Nuget mal ansehen:)

    Und zwecks Performance sollte ja trotzdem der MemStream schneller sein als ein FileStream und man braucht weniger Schreibvorgänge?
    Seh ich das richtig so?

    n1nja schrieb:

    Ich mein die Var direkt selbst. Wenn ich die speicher ist sie allein schon über 1mb. Was ungewöhnlich ist.
    Na gut, ich habe bisher auch nie versucht eine FileInfo zu serialisieren.

    n1nja schrieb:

    Und zwecks Performance sollte ja trotzdem der MemStream schneller sein als ein FileStream und man braucht weniger Schreibvorgänge?
    Seh ich das richtig so?
    Du versuchst Äpfel mit birnen zu vergleichen. MemoryStream und FileStream haben verschiedene Aufgaben. Wenn es nur darum geht Bytes in einen Stream zu schreiben, und wieder auszulesen, gewinnt natürlich der MemoryStream, ist ja direkter RAM zugriff, wohingegen der FileStream die bytes ja direkt auf die Platte schreibt, und dann wieder liest. Wennde da so ne Notebook HDD hast, kann das schonmal langsam vonstatten gehen. Aber wie schon gesagt, verschiedene Streams haben verschiedene Aufgaben, und mann muss für die richtige Aufgabe den Richtigen Stream nehmen. Mit nem MemoryStream kannste halt in keine Dateien schreiben, und mit dem FileStream kannste nicht in den RAM schreiben.

    Um nun konkret auf dein Vorhaben einzugehen:
    Du list dir per FileInfo sätmliche wichtigen Infos aus, und erzeugst dann aus dieser FileInfo-Klasse heraus den FileStream, denn du dann, wie ich oben gezeigt habe, durch den GZip und CryptoStream jagst, um dann das ganze mit einem zweiten FileStream an deinen Wunschort zu legen. Willst du die Datei weiderherstellen, führst du dasselbe genau verkehrt herum durch. Mit dem FileStream einlesen, durch den Crypto und GzipStream und dann wieder mit nem FileStream auf die Platte.
    Oke ja das habe ich bis jetzt verstanden.

    Naja so alt ist diese Platte nicht. Ist ne M2 SSD :)

    Und zum Thema FileInfo. Ja genau im mom ist sie auch in meiner Klasse drin so brauch ich nicht extra Properties für Länge, Datum usw.

    Lesen und Schreiben tue ich im Mom die Bytes mit den System.IO.File Namespace.

    Aber gut mit den Filestream werd ich das auf jedenfall mal testen, solang der BinaryFormatter in nen FileStream schreiben lässt, das weis ich grad nicht.
    Danke aber so meinte ich das nicht:)

    Eher ob man mit dem BinaryFormatter innen FileStream schreiben kann und nicht nur MemStream.
    Kanns leider immernoch nicht sehen. Kein VS grad da:)

    Ok habs eben nachgelesen, die Methode nimmt Stream, Object.
    Sollte also gehn.

    Dann mach ich mich nach der Arbeit drüber und berichte :)

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „n1nja“ ()

    Sooo.

    Hab jetzt bissl was abgeändert und scheint "erstmal" zu funktionieren.
    Bis jetzt ohne Verschlüsslung, nur gezippt.

    Hab halt jetzt das Problem das ich die File nicht direkt mit der Klasse abspeichern kann.
    Denke hier wird die einzige Lösung sein, das ich die Datei mit nen Buffer einlese und am Ende die Klasse ranhänge und mit nen zweiten FileStream Datei + Klasse abspeichere.

    Oder habt ihr da auch ne andere Idee?


    Spoiler anzeigen

    C#-Quellcode

    1. public Filedrops(ClipboardObj Clipboard)
    2. {
    3. _clipboard = Clipboard;
    4. }
    5. private ClipboardObj _clipboard;
    6. public ClipboardObj Clipboard { set { _clipboard = value; } get { return _clipboard; } }
    7. public List<FiledropInfo> DropList { set; get; } = new List<FiledropInfo>();
    8. public long FiledropSize { set; get; }
    9. [Serializable]
    10. public struct FiledropInfo
    11. {
    12. public string Path { set; get; }
    13. public string FileHash { set; get; }
    14. public bool IsFile { set; get; }
    15. public byte[] FileData { set; get; }
    16. }


    Das is ma die Filedrops Klasse die ich serialisiert abspeichere. Vorher war "FileData" die Datei.
    Nun generier ich den Hash dazu ich speicher die Datei und die Klasse in 2 Dateien ab.

    FileDropInfo is pro Datei im Zwischenspeicher. FileDrops ist das ganze Clipboard.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „n1nja“ ()

    n1nja schrieb:

    Hab halt jetzt das Problem das ich die File nicht direkt mit der Klasse abspeichern kann.
    ich hab schon wieder VErsteh-Probleme: "die File mit der Klasse abspeichern"? Was bedeutet das?

    In meiner Welt ist vorstellbar, ein Objekt in ein File abzuspeichern, auch mehrere Objekte ins selbe File. Serialisierung kann man dazu verwenden.
    Aber ich bekomme keine Übereinstimmung hin mit meiner Sicht der Welt und deinem Satz - also er ergibt bei mir schlicht keinen Sinn.
    Ok dann nochmal.

    Die Klasse wird gespeichert. Daran befindet sich als ByteArray die Datei. Siehe "FileData".

    Das hatte ich abgeändert um die RAM Auslastung gering zu halten. Deswegen wird die Datei per FileStream abgespeichert.

    Und jetzt hab ich das Problem, das ich die Klasse inkl. die Datei nicht mehr zusammen abspeichern kann.