c# und häufiges new



  • Hallo!

    bin neu in C# und komme eigentlich von C++. Ich sitz grad an einem Code, wo häufig sowas vorkommt:

    foreach(Point p in Liste)
    {
        graphics.draw(p, new Pen(Color.Red));
    }
    

    Ist das in Ordnung oder macht sich das bei vielen Punkten erheblich bemerkbar, dass so oft neue Pens erstellt werden, obwohl einer reicht. Also ist das so allgemein üblich in C# oder wäre folgendes erheblich besser?

    Pen p = new Pen(Color.Red);
    foreach(Point o in Liste)
      graphics.draw(o, p);
    

    Oder ist der Garbage-Collector so gut, dass er sofort merkt, dass das Objekt ncih mehr benutzt wird?



  • ne so gut ist der GC glaub net.. denke deine variante wie du sie in C++ machen würdest sollte funktionieren;)

    oder so

    foreach(Point p in Liste)
    {
      using(Pen o = new Pen(Color.Red)){
        graphics.draw(p,o));
       }
    
    }
    

    das Pen object "o" lebt nur im using block.. weis aber net ob das so richtig ist;)



  • Hallo

    oder rufst Dispose() händisch auf... (oder du lässt es einfach)

    chrische



  • Generell räumt der GC auf. Bei dem System.Drawing Zeugs sollte man aber berücksichtigen, das da u.U. native Ressourcen gesperrt werden und das so lange bis der GC aufräumt.

    using(Pen p = new Pen(Color.Red))
    {
    foreach(Point o in Liste)
      graphics.draw(o, p);
    }
    

    Telefonieren und Posten dauert zu lange =o)



  • Wenn Du immer dieselben Stifte benötigst kannst Du diese auch in einer Factory einmal beim ersten Abruf erzeugen und dann immer dieselben Objektreferenzen übergeben.



  • Danke erstmal.

    Das mit dem Pen war nur ein Beispiel von vielen. Das mit en nativen Resourcen ist wahrscheinlich ein Grund, nicht so oft new aufzurufen. Ich denke, ich werde es so lösen, dass in jeder Klasse eine statische Variable pen drin ist, die dann von allen benutzt wird, damit spart man sich eine Menge new-Aufrufe.

    Aber wie siehts mit normalen Objekten aus? Zum Beispiel wenn ich folgendes habe:

    foreach(Vector3D v in Liste)
    {
      draw(new Point3D(v));
    }
    

    Hier wird das Point3D-Objekt nur gebraucht, um das v zu zeichnen. In c++ würde einfach ein Objekt auf dem Stack liegen und nach dem Funktionsaufruf ist es wieder freigegeben, in C# ja nicht.

    Ich weiß, ich könnte eine Funktion bereitstellen, die gleich ein Vector3D als Parmaeter nimmt, aber darum soll es hier nicht gehen. Sind übermäßig viele new-aufrufe schädlich/verlangsamend, oder ist C# dafür wirklcih angelegt, dass man mit Resourcen rumwirtschaftet wie man will und sich auf den GC verlässt?



  • Warum glaubst du macht sogar Microsoft ein Dispose.

    http://msdn.microsoft.com/en-us/library/system.drawing.pen.aspx
    Manches gehört in NET händisch gelöscht.



  • Maxi schrieb:

    Sind übermäßig viele new-aufrufe schädlich/verlangsamend,

    ja, ist pöse.
    du erzwingst dadurch viele collections. gen 0 collections sind zwar normal recht schnell, aber viele collections führen im endeffekt auch fast immer dazu, dass auch gen 2 collections unnötig oft gemacht werden müssen, und gen 2 collections sind vergleichsweise langsam.

    oder ist C# dafür wirklcih angelegt, dass man mit Resourcen rumwirtschaftet wie man will und sich auf den GC verlässt?

    funktionieren tut es schon, aber s.o., es wird halt langsamer.

    ---

    bloss... wenn Point3D ein value-type ist, dann müsste es AFAIK egal sein, weil C# den genauso "auf den stack legt", wie man es in C++ machen würde.



  • hustbaer schrieb:

    Maxi schrieb:

    Sind übermäßig viele new-aufrufe schädlich/verlangsamend,

    oder ist C# dafür wirklcih angelegt, dass man mit Resourcen rumwirtschaftet wie man will und sich auf den GC verlässt?

    funktionieren tut es schon, aber s.o., es wird halt langsamer.

    ok, dann werd ich versuchen, das einzudämmen.

    hustbaer schrieb:

    bloss... wenn Point3D ein value-type ist, dann müsste es AFAIK egal sein, weil C# den genauso "auf den stack legt", wie man es in C++ machen würde.

    Point3D ist auch eine Klasse, kein struct oder enum, also liegt sie nciht auf dem stack, oder?



  • hustbaer schrieb:

    Maxi schrieb:

    Sind übermäßig viele new-aufrufe schädlich/verlangsamend,

    ja, ist pöse.
    du erzwingst dadurch viele collections. gen 0 collections sind zwar normal recht schnell, aber viele collections führen im endeffekt auch fast immer dazu, dass auch gen 2 collections unnötig oft gemacht werden müssen

    Warum?



  • Weil Baum!



  • Helium schrieb:

    hustbaer schrieb:

    Maxi schrieb:

    Sind übermäßig viele new-aufrufe schädlich/verlangsamend,

    ja, ist pöse.
    du erzwingst dadurch viele collections. gen 0 collections sind zwar normal recht schnell, aber viele collections führen im endeffekt auch fast immer dazu, dass auch gen 2 collections unnötig oft gemacht werden müssen

    Warum?

    Warum was?

    z.B. weil bei jeder Collection alle "überlebenden" Objekte eine Generation weiter wandern. Dadurch wird die Gen 2 (=letzte Generation) immer grösser, und das Gen 2 Limit wird schneller/öfter erreicht.

    In so gut wie jeder Sprache gilt eben "viel new = viel schlecht", sei's nun mit oder ohne GC.

    Natürlich gilt auch hier wieder die 80/20 Regel - nur damit das jetzt keiner misversteht. Und in vielen Programmen werden die 80 u.U. auch 100 sein.



  • Maxi schrieb:

    In c++ würde einfach ein Objekt auf dem Stack liegen und nach dem Funktionsaufruf ist es wieder freigegeben, in C# ja nicht.

    Selbst in C++ würde ich die Variable hier vor der Schleife erstellen, denn unabhängig von Garbage Collector oder sonstiger Speicherverwaltung sind es einfach weniger Schritte:

    for (int i = 0; i < 10; i++)
    {
        int x = 5;
    
        cout << x;
    }
    

    -->
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;

    int x = 5;
    for (int i = 0; i < 10; i++)
    {
        cout << x;
    }
    

    -->
    int x = 5;
    cout << x;
    cout << x;
    cout << x;
    cout << x;
    cout << x;
    cout << x;
    cout << x;
    cout << x;
    cout << x;
    cout << x;



  • Maxi schrieb:

    Point3D ist auch eine Klasse, kein struct oder enum, also liegt sie nciht auf dem stack, oder?

    Nein, Objekte werden auf dem Heap angelegt! Die Referenz auf das angelegte Objekt, die du erhälst, wird auf dem Stack gespeichert!

    Grüße



  • for (int i = 0; i < 10; i++)
        cout <<5;
    


  • Hupf schrieb:

    Maxi schrieb:

    Point3D ist auch eine Klasse, kein struct oder enum, also liegt sie nciht auf dem stack, oder?

    Nein, Objekte werden auf dem Heap angelegt! Die Referenz auf das angelegte Objekt, die du erhälst, wird auf dem Stack gespeichert!

    Grüße

    Value types werden auch direct auf dem Stack angelegt.



  • Jenna J. schrieb:

    Maxi schrieb:

    In c++ würde einfach ein Objekt auf dem Stack liegen und nach dem Funktionsaufruf ist es wieder freigegeben, in C# ja nicht.

    Selbst in C++ würde ich die Variable hier vor der Schleife erstellen, denn unabhängig von Garbage Collector oder sonstiger Speicherverwaltung sind es einfach weniger Schritte:

    for (int i = 0; i < 10; i++)
    {
        int x = 5;
    
        cout << x;
    }
    

    -->
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;
    int x = 5
    cout << x;

    int x = 5;
    for (int i = 0; i < 10; i++)
    {
        cout << x;
    }
    

    -->
    int x = 5;
    cout << x;
    cout << x;
    cout << x;
    cout << x;
    cout << x;
    cout << x;
    cout << x;
    cout << x;
    cout << x;
    cout << x;

    Jeder vernünftige Compiler optimiert dir das, so dass beide Varianten genau gleich schnell sind.

    Variablen immer "so lokal wie möglich", also in diesem Fall innerhalb der Schleife, nicht davor. Warum? Weil's übersichtlicher ist!



  • hustbaer schrieb:

    Variablen immer "so lokal wie möglich", also in diesem Fall innerhalb der Schleife, nicht davor. Warum? Weil's übersichtlicher ist!

    Woher soll ich das auch so genau wissen? Ich komme schließlich aus einer anderen Branche.



  • J. Jameson schrieb:

    hustbaer schrieb:

    Variablen immer "so lokal wie möglich", also in diesem Fall innerhalb der Schleife, nicht davor. Warum? Weil's übersichtlicher ist!

    Woher soll ich das auch so genau wissen? Ich komme schließlich aus einer anderen Branche.

    Das ist auch keine absolute Wahrheit, sondern meine Meinung 🙂
    Davon abgesehen: jetzt weisst dus ja. Ist ja nix passiert... 😕



  • Value types werden auch direct auf dem Stack angelegt.

    wie sind die denn unterscheidbar?? blau-> stack -> grün ->heap ??? seh ich das richtig^;)


Log in to reply