Stackoverflow bei instanzierung eine großen Objekts.



  • @wob sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    Gibt es denn die Möglichkeit, den Codegenerator umzuschreiben?
    Das hier
    this.Object_00001 = new ObjectX();
    this.Object_00002 = new ObjectX();
    this.Object_00003 = new ObjectX();

    stinkt doch ganz grausam nach einem Array von ObjectX. Außderdem: was für Compilezeiten kommen denn raus, wenn man 50k Variablen hat?!

    ja es ist grausam, ich weiß... aber das Problem ist . den Code Generator kann man umbschreiben, ABER:

    das ist nur ein pseude code, in wirklichkeit ist Das ObjectX irgend ein generiertes Object ,welches auch Properties hat.

    hier etwas komplexter pseudo:

    class MyBigObject
    {
       public MyBigObject()
       {
       this.Root = new ObjectX(); //ObjectX hat ein feld A ,usw.
       this.Root.A = new ObjectY();
       this.Root.B = new ObjectZ();
      this.Root.B.A = new ObjectA();
       // und das ganze in irgendeiner form 50000 mal.
       }
    }
    

    Ich könnte jetzt dem MyBixObject ein string json geben, und anhand der json file, das ganze model auch erstellen lassen, ohen den statischen code. das wäre die "not" lösung.

    Aber ich versuche noch zu verstehen wie ich nen optimierten generieten code machen könnte..



  • @SoIntMan sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    class MyBigObject
    {
       public MyBigObject()
       {
       this.Root = new ObjectX(); //ObjectX hat ein feld A ,usw.
       this.Root.A = new ObjectY();
       this.Root.B = new ObjectZ();
      this.Root.B.A = new ObjectA();
       // und das ganze in irgendeiner form 50000 mal.
       }
    }
    

    Dein Problem ist doch, dass du zu viele Variablen in MyBigObject hast, d.h. root1, root2, root3 etc, oder?

    Dann wird da eben folgendes draus:

    this.root[0] = new RootObject();
    this.root[0].A = ...
    this.root[0].B = ...
    ...
    this.root[50k] = new RootObject();
    this.root[50k].A = ...
    this.root[50k].B = ...
    

    Ich kann sonst auch nichts dazu sagen. Ein Umbau so erscheint mir aber einfacher als irgendwie auf einmal einen String zu parsen, wobei vielleicht letztes für dich auch sinnvoll ist, wenn die Klassen ObjectX/Y/Z eigentlich nur irgendwelche Daten halten und keine Funktionalität haben.



  • @SoIntMan: Was mir noch eingefallen ist: schau dir mal den IL-Code des Konstruktors an (z.B. mit ILSpy) und überprüfe mal, ob dort ein oder mehrere .maxstack-Anweisungen drin sind (diese sollten eigentlich nur bei lokalen Variablen und nicht bei direkten Zugriffen auf die Klassenmember benötigt werden).
    Aber probiere auch mal die Release-Version aus.



  • Vielleicht ist auch das Problem dass der JIT nen Stack-Overflow verursacht beim Versuch die lange Funktion zu optimieren. Das würde auch dazu passen dass er das Programm abbricht statt dir eine StackOverflowException zu werfen.

    Wie ist denn der Callstack von dem Crash?



  • @wob sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    Dein Problem ist doch, dass du zu viele Variablen in MyBigObject hast, d.h. root1, root2, root3 etc, oder?

    Nein , die MyBigObject class hat ein Root Member vom Typ X, der Type X hat Member Type Irgendwas und das in eine n-ten hierachy, d.h. ich habe ein Baumsturkt und keine flache feld hierarchy.

    Leider kan ich ein Array nicht verwenden, da die Felter (Property) konkret sein müssen. Ich mag das konzept auch nicht aber das haben leute eben so beschlossen.

    @Th69 sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    @SoIntMan: Was mir noch eingefallen ist: schau dir mal den IL-Code des Konstruktors an (z.B. mit ILSpy) und überprüfe mal, ob dort ein oder mehrere .maxstack-Anweisungen drin sind (diese sollten eigentlich nur bei lokalen Variablen und nicht bei direkten Zugriffen auf die Klassenmember benötigt werden).
    Aber probiere auch mal die Release-Version aus.

    ok das muss ich mal sehen

    @hustbaer sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    Vielleicht ist auch das Problem dass der JIT nen Stack-Overflow verursacht beim Versuch die lange Funktion zu optimieren. Das würde auch dazu passen dass er das Programm abbricht statt dir eine StackOverflowException zu werfen.
    Wie ist denn der Callstack von dem Crash?

    ja das passiert ab und an.. OutOfMemory oder VS stürzt ohne meldung ab 🙂



  • @SoIntMan sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    class MyBigObject
    {
       public MyBigObject()
       {
       this.Root = new ObjectX(); //ObjectX hat ein feld A ,usw.
       this.Root.A = new ObjectY();
       this.Root.B = new ObjectZ();
      this.Root.B.A = new ObjectA();
       // und das ganze in irgendeiner form 50000 mal.
       }
    }
    

    Ich habe keine Ahnung von C#, aber wenn es ein Problem ist, dass die Source Datei zu groß ist, weil alles in MyBigObject() passiert, würde ich das verlagern, also z.B. die Variable this.Root.B.A im Konstruktor von ObjectZ() erstellen.

    @SoIntMan sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    ja das passiert ab und an.. OutOfMemory oder VS stürzt ohne meldung ab

    Vlt wäre es eine Möglichkeit schonmal VS 2022 auszuprobieren, dann mit 64 bit Unterstützung. Das könnte an der Stelle helfen.



  • 50 kloc+ in einer Funktion ist in modernen Hochsprachen einfach keine gute Idee. Quasi sämtliche Teile der Kette sind nicht darauf ausgelegt das zu verdauen, und speiben sich dementsprechend auch regelmässig an bei sowas. Der Umstand dass der Code super einfach ist, keine Schleifen enthält etc. ändert daran leider nichts.



  • Ein möglicher Workaround wäre den Code-Generator so umzustellen dass er z.B. für je 100~1000 Zeilen eine Funktion generiert, diese alle mit [MethodImpl(MethodImplOptions.NoInlining)] markiert und dann alle hintereinander im ctor aufruft.
    Kann nicht garantieren dass es hilft, aber wäre mMn. Wert dass man es ausprobiert.



  • @Schlangenmensch sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    Ich habe keine Ahnung von C#, aber wenn es ein Problem ist, dass die Source Datei zu groß ist, weil alles in MyBigObject() passiert, würde ich das verlagern, also z.B. die Variable this.Root.B.A im Konstruktor von ObjectZ() erstellen.

    Das ist ein guter Vorschlag, das habe ich mir auch schon überlegt. Leider erlaubt diese das aktuellen Software design nicht, und das zu ändern ist nicht gewollt, und zudem ein mega aufwand.

    @Schlangenmensch sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    @SoIntMan sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    ja das passiert ab und an.. OutOfMemory oder VS stürzt ohne meldung ab

    Vlt wäre es eine Möglichkeit schonmal VS 2022 auszuprobieren, dann mit 64 bit Unterstützung. Das könnte an der Stelle helfen.

    ja das wäre ne Notlösung. ich sag's euch, Katastrophe die Leute da;=)

    @hustbaer sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    50 kloc+ in einer Funktion ist in modernen Hochsprachen einfach keine gute Idee. Quasi sämtliche Teile der Kette sind nicht darauf ausgelegt das zu verdauen, und speiben sich dementsprechend auch regelmässig an bei sowas. Der Umstand dass der Code super einfach ist, keine Schleifen enthält etc. ändert daran leider nichts.

    bin ganz deiner Meinung. Ich hätte das ganz anderes gemacht, aber die Urheber damals waren halt keine Architekten. Damals war das Objekt gar nich so umfangreich, aber es skaliert hat gerade gar nicht mehr. Ich würde es gern anpassen, aber das kostet zudem Geld;) und die leute kapieren es nicht das es ein großem problem is.

    @hustbaer sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    Ein möglicher Workaround wäre den Code-Generator so umzustellen dass er z.B. für je 100~1000 Zeilen eine Funktion generiert, diese alle mit [MethodImpl(MethodImplOptions.NoInlining)] markiert und dann alle hintereinander im ctor aufruft.
    Kann nicht garantieren dass es hilft, aber wäre mMn. Wert dass man es ausprobiert.

    du meinst ich soll die ca 50000 zeilen in 50 funktion splitten mit dem attribute?



  • @SoIntMan sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    du meinst ich soll die ca 50000 zeilen in 50 funktion splitten mit dem attribute?

    Ja. Wenn du das ohne grossen Aufwand machen kannst, wäre das einen Versuch wert.



  • @hustbaer sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    Ja. Wenn du das ohne grossen Aufwand machen kannst, wäre das einen Versuch wert.

    klar, ich kann auch jede zeile in ne funktion auslagern;) das Proble ich glatt aus;) es funktioniert momenta (gerade so am limit) aber das mache ich .. danke dir.

    Aber eine rein technische frage dazu:

    Würde ich bspw. die Zeile

    this.x = new ObjectX();
    

    n eine Function

    void Create<T>(ref T target) : where T: class, new()  { target = new T(); }
    

    dann im ctor

    Create<ObjectX>(ref this.x);
    

    kapseln, würde der Compiler dann für jeden call ein sprungbefehlt zur Funktion setzen, oder die Funktion n-mal an der stelle , ich nehme an dass du genau das mit nem notInline meinst gell.



  • @SoIntMan
    Also meine Idee war die, dass der JIT vielleicht einfach dadurch langsam wird und viel Speicher braucht, dass die Funktion so riesig ist. Wäre vorstellbar dass da Dinge passieren die nicht linear skalieren sondern schelchter. Also z.B. dass der JIT z.B. 4x länger braucht (und vielleicht auch 4x so viel Stack), wenn die Funktion 2x länger wird.

    In dem Fall kann es etwas bringen die Funktion in mehrere Stücke zu zerteilen. Nun gibt es aber - zumindest in C++ Compilern - eine Optimierung, die dann greift wenn die Funktion nur an einer einzigen Stelle aufgerufen wird. Diese werden viel eher inlined als Funktionen die an vielen Stellen aufgerufen werden. Grund ist einfach: wenn ich eine eher lange Funktion habe, und die an 100 Stellen inline, dann verschwende ich enorm Speicher. Wenn die Funktion dagegen nur an einer Stelle aufgerufen wird, dann ist es nicht wirklich wichtig wie lange die ist.
    Daher hab ich sicherheitshalber empfohlen das "no inline" Attribut dranzuschreiben. Um zu verhindern dass der JIT sieht dass die Funktion nur an der einen Stelle aufgerufen wird, und beschliesst sie zu inlinen, trotz dem sie recht gross ist. Keine Ahnung ob das passieren würde, aber ich denke ein "no inline" Attribut an der Stelle kann nicht schaden.

    Um was es mir hauptsächlich ging ist aber eher einfach zu verhindern dass so grosse Funktionen geJITed werden müssen. Und da wäre dann jede einzelne Zeile in eine Funktion zu packen wieder kontraproduktiv. Weil du dann ja wieder eine grosse Funktion brauchst die alle kleinen aufruft.

    Ob es überhaupt am JIT liegt kannst du aber relativ einfach ausprobieren. Wenn es am JIT liegt, dann sollte nur der 1. Aufruf der Funktion ein Problem sein. Weitere Aufrufe sollten dann auch ohne vergrösserten Stack gehen, und auch viel schneller laufen.



  • @hustbaer sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    Ob es überhaupt am JIT liegt kannst du aber relativ einfach ausprobieren. Wenn es am JIT liegt, dann sollte nur der 1. Aufruf der Funktion ein Problem sein. Weitere Aufrufe sollten dann auch ohne vergrösserten Stack gehen, und auch viel schneller laufen.

    Also was mir eben aufgefallen ist, dass (im Debugger) wenn ich ein Breakpoint zur ersten Zeile (Funktion) setzt, und der Breakpoint erreicht wird. dann is alles in Butter und er ratterst die 50 Zeilen vollgas durch.

    Aber von CreateInstance<MyBigObject>() bis zum Breakpoint der ersten Zeile in Ctor des MyBigObject. sehe ich im Diagnose tool VS dass der Speicher auf 1,3GB ansteigt, dann absinkt auf 200MB und dann zum Breakpoint hängt.
    Das dauert 10-15sekunden , und da kann eben ein OutOfMemory kommen oder ein StackOverflow.. aber wenn er dann im ctor hängt passiert nichts mehr (außer ich würde evlt. in den 50k Zeilen zu viel Speicher allokieren dass es dann dock knallt=)

    Weißt wie ich mein?)



  • @SoIntMan sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    Aber von CreateInstance<MyBigObject>() bis zum Breakpoint der ersten Zeile in Ctor des MyBigObject. sehe ich im Diagnose tool VS dass der Speicher auf 1,3GB ansteigt, dann absinkt auf 200MB und dann zum Breakpoint hängt.
    Das dauert 10-15sekunden , und da kann eben ein OutOfMemory kommen oder ein StackOverflow.. aber wenn er dann im ctor hängt passiert nichts mehr (außer ich würde evlt. in den 50k Zeilen zu viel Speicher allokieren dass es dann dock knallt=)

    Das klingt würde ich sagen sehr nach JIT. Aber...

    Weißt wie ich mein?)

    Nein, bin nicht sicher ob ich das richtig verstehe. Was macht denn CreateInstance<MyBigObject>()? Bisher hast du immer von new MyBigObject geschrieben. (Bzw. 1x new ObjectX wo aber vermutlich new MyBigObject gemeint war.)

    Und: hast du denn ausprobiert was passiert wenn du den Code 2x hintereinander ausführst (natürlich ohne das Programm 2x zu starten)?



  • @hustbaer sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    Nein, bin nicht sicher ob ich das richtig verstehe. Was macht denn CreateInstance<MyBigObject>()? Bisher hast du immer von new MyBigObject geschrieben. (Bzw. 1x new ObjectX wo aber vermutlich new MyBigObject gemeint war.)

    sorry für Verwirrung, ich meinte ich hatte die allokieren in ein funktion ausgelagert, weil ich vorhatte evtl. business logig zu kapseln, aber bisher siehtes einfach so aus.

    T x = CreateInstance<T>() where T: class, new() => new T() ;
    

    genau ich meinte im Prinzip immer n```csharp
    ew MyBigObject().

    hmm ok 2 mal hintereiander also :

    var a = new MyBigObject ();
    var b = new MyBigObject ();
    

    du vermutest dass es dann nur bei de ersten Zeile so lang dauert, und bei de 2-ten dann nich mehr , hab ich recht!?

    Muss ich heute abend mal ausprobieren



  • @SoIntMan sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    du vermutest dass es dann nur bei de ersten Zeile so lang dauert, und bei de 2-ten dann nich mehr , hab ich recht!?

    Ja. Oder sagen wir so: wenn es am JIT liegt, dann müsste das so sein. Bzw. auch umgekehrt: wenn es so ist, dann liegt es ziemlich sicher am JIT.



  • @hustbaer sagte in Stackoverflow bei instanzierung eine großen Objekts.:

    Ja. Oder sagen wir so: wenn es am JIT liegt, dann müsste das so sein. Bzw. auch umgekehrt: wenn es so ist, dann liegt es ziemlich sicher am JIT.

    Alles klar Kommender ich kam bisher nicht dazu , heute probiere ich es 😉

    EDIT: @hustbaer Ja die zweite Instanziierung scheint schneller zu gehen;)


Anmelden zum Antworten