Wie heißt der Nachfolger ...



  • Hallo,
    ganz interessant zum Thema ist auch das Topic "Will C++0X have a gc?" das im Oktober in der Newsgroup comp.std.c++ diskutiert wurde.



  • Original erstellt von kartoffelsack:
    **Templates (habt ja gesagt, die solls jetzt doch geben),
    **

    gibt es auch, aber sie müssen explizit instanziiert werden.
    Klassen und Interfaces

    [ Dieser Beitrag wurde am 26.11.2002 um 12:54 Uhr von Noesis editiert. ]



  • Noch mal zum Thema GC. Ist ein GC wirklich besser, als Smartpointer.

    Der GC muss bei jedem Objekt überprüfen, ob er es löschen darf. dazu muss er doch semtliche Referenzen überprüfen, ob diese nicht auf dieses Objekt verweisen.

    Smartpointer wissen, wann es keine Referenz mehr auf das Objekt gibt und müssen nicht danach suchen.

    Vielleicht sollte man aber auch eine mischung verwenden (oder wird es in Java schon so gelößt?): Die Referenzen sind eine Art Smartpointer, die das Objekt aber nicht selbstständig löschen, sondern nur einer Art GC mitteilen, wenn sie zerstört werden. So muss der GC nichts suchen, sondern wiß immer, wann er ein Objekt zerstören darf.



  • Original erstellt von volkard:
    **
    Wenn ich nur kurz Speicher anlege, was damit mache, und dann sofort wegwerfe, dann schreib vorne ein new und hinten ein delete und keine Architektur mit Zwangs-GC kann genausso billig sein.
    Macht zwar nur ein paar Takte aus, aber in C++ gehörts zu den Regeln, daß man nix zahlen muß für was, was man nicht braucht.**

    Verstehe ich nicht. Es ist IMHO schneller, sich mit einem vernünftigen GC Speicher für ein Objekt zu holen, als ohne. Das Löschen dauert mit GC natürlich länger, es wird aber nicht gleich gelöscht, wenn das Objekt nicht mehr benötigt wird. In Java gibt es 2 Stellen, an denen der GC aktiv wird und Speicher wieder freigibt :

    1. Wenn der Speicher voll ist.
    2. Wenn man den GC per Hand aufruft. Natürlich macht man das in der Regel an Punkten, an denen man ansonsten keine Performance benötigt.

    Natürlich ist ein GC langsamer, wenn man in einer Schleife, die oft durchlaufen wird, immer ein kleines Objekt erzeugt und kurz danach wieder zerstört. ...aber ich denke, solche Objekte sollten eh auf den Stack, oder?! 🙂 ...da hat der GC doch eher nichts verloren.



  • Was sagt ihr denn zu den "neuen Features"?

    Ich denke, folgendes gibt es in C++ so nicht, ich habe es zumindest noch nicht gesehen :

    1. Vorbedingungen und Nachbedingungen für Methoden
    2. Der Bit-Datentyp
    3. Threads als Teil der Standardbibliothek
    ...



  • 1. Vorbedingungen und Nachbedingungen für Methoden

    Gibt's meines Wissens nach nur in Eiffel. In C++ kann man dies aber im Gegensatz zu Java noch relativ einfach einbauen. Einfach Template-Method anwenden:

    class Base
    {
    public:
         void Func()
         {
              // Vorbedingungen prüfen
              do_Func();
              // Nachbedingungen prüfen
         }
    private:
         virtual void do_Func()
         {
             // Algorithmus hier
         }
    };
    
    class Derived : public Base
    {
    public:
    // öffentliches Interface in Ruhe lassen
    private:
         void do_Func()
         {
             // spezialisierter Algo hier
         }
    };
    

    Ist sicher nicht perfekt, aber auch nicht ganz schlecht.

    2. Der Bit-Datentyp

    Es gibt bitsets. Bit als Datentyp wird ist meiner Meinung nach aber wohl niemals geben. Die kleinste adressierbare Einheit in C und C++ war und ist Byte.

    3. Threads als Teil der Standardbibliothek

    Irgendeine Form von Threads wird's im C++0X wohl geben. Und wenn es nur eine Spezifikation (so wie bei den STL-Containern und Algorithmen )ist.



  • versioning?
    also z.b. debug/release spez. code ohne makros realisieren zu können.
    (zb ein compiler assert)



  • Original erstellt von Gregor:
    Verstehe ich nicht. Es ist IMHO schneller, sich mit einem vernünftigen GC Speicher für ein Objekt zu holen, als ohne.

    Und das versteh ich nicht. Wodurch soll Speicher schneller verfügbar sein, nur weil ein GC da ist? Nimmst Du an, in C++ werde immer sofort jede freie Speicherseite dem BS zurückgegeben? Das ist wohl kaum der Fall, wäre ja auch viel zu lahm.



  • So! Ich habe jetzt einfach mal 2 Programme geschrieben, die größtenteils das Gleiche machen. Eins in C++, das andere in Java. Es geht darum, wie schnell Objekte auf dem Heap erzeugt/gelöscht werden können. Das Ergebnis überrascht mich selbst etwas. Wahrscheinlich habe ich beim C++-Programm goßen Unsinn gemacht. Ich fange ja schließlich gerade erst mit C++ an!

    C++-Programm :

    main.cpp :

    #include <iostream>
    #include <stdlib.h>
    #include <ctime>
    #include "TestClass.h"
    
    int main(int argc, char *argv[])
    {
      int size = 3000000;
      long long sum = 0;
      clock_t time;
    
      TestClass ** array = new TestClass* [size];
      time = clock();
      for (int i = 0 ; i < size ; ++i)
      {
        array[i] = new TestClass(i);
      }
      std::cout << clock() - time << std::endl;
      time = clock();
      for (int i = 0 ; i < size ; ++i)
      {
        sum += array[i]->getNumber ();
        delete array[i];
      }
      delete [] array;
      std::cout << clock() - time;
    
      system("PAUSE");   
      return 0;
    }
    

    TestClass.h :

    class TestClass
    {
       private :
       int number;
    
       public :
       TestClass ()
       {
       }
    
       TestClass (int i)
       : number (i)
       {
       }
    
       ~TestClass ()
       {
       }
    
       int getNumber ()
       {
          return number;
       }
    
       void setNumber (int i)
       {
          number = i;
       }
    };
    

    Java-Programm :

    TestMemory.java :

    public class TestMemory
    {
    
       /** Creates a new instance of TestMemory */
       public TestMemory ()
       {
       }
    
       public static void main (String [] args)
       {
          int size = 3000000;
          long sum = 0; 
          long time;
          TestClass [] array = new TestClass [size];
          time = System.currentTimeMillis ();
          for (int i = 0 ; i < size ; ++i)
          {
             array[i] = new TestClass(i);
          }
          System.out.println (System.currentTimeMillis () - time);
          time = System.currentTimeMillis ();
          for (int i = 0 ; i < size ; ++i)
          {
             sum += array[i].getNumber ();
             array[i] = null;
          }
          array = null;
          System.out.println (System.currentTimeMillis () - time);
          time = System.currentTimeMillis ();
          System.gc();
          System.out.println (System.currentTimeMillis () - time);
          System.out.println (sum);
       }
    
       private static class TestClass
       {
          private int number;
    
          public TestClass (int i)
          {
             number = i;
          }
    
          public void setNumber (int i)
          {
             number = i;
          }
    
          public int getNumber ()
          {
             return number;
          }
       }
    }
    

    Das Ergebnis ist folgendes :
    Java braucht zum Erzeugen etwa 2 Sekunden, C++ mehr als 2,5 Sekunden. Java braucht zum Löschen keine 200ms, C++ braucht wieder mehr als 2,5 Sekunden. Ich denke, das Java-Programm bricht ab, bevor es mit dem Löschen fertig ist. Anders kann ich mir das nicht erklären.



  • @Gregor: wie schnell ist dein prozessor?



  • Original erstellt von volkard:
    @Gregor: wie schnell ist dein prozessor?

    1,2 GHz P4M (bzw. 1,6 GHz, aber runtergetaktet, es lief aber auch noch was im Hintergrund. Bei beiden Programmen das gleiche, die Ergebnisse waren trotzdem reproduzierbar)



  • lole:

    import c.stdio;
    import windows;
    
    class BigClass {
        int number;
    }
    
    int main () {
        const int size = 3000000;
    
        int start = GetTickCount ();
    
        BigClass [] BC = new BigClass [size];       
    
        int end = GetTickCount ();
        printf ("Benoetigte Zeit: %i", end-start);
    
        return 0;
    }
    

    Witzigerweise ist dieser Code in D in der Debug Version um rund 40 Millisekunden schneller... (40ms)



  • Achja, an alle nette Leute, die der Garbage Collector in D stört:
    Hier klicken

    [ Dieser Beitrag wurde am 26.11.2002 um 23:53 Uhr von Noesis editiert. ]



  • @ Noesis : Bau doch mal ein Programm, das in D tatsächlich das Gleiche macht, wie das C++-Programm. Du erzeugst ja bisher nur ein großes Array. In den anderen Programmen werden auch noch ganz viele kleine Objekte erzeugt. ...und dann wieder gelöscht!

    EDIT : ...oder werden die Objekte da schon miterzeugt?

    [ Dieser Beitrag wurde am 27.11.2002 um 00:03 Uhr von Gregor editiert. ]



  • Ähm, hollo, ich bin *noch* kein D Spezialist, aber mir bringt er die Fehlermeldung, wenn ich statische Arrays (arrays mit fixer Größe erzeuge, Typ [const größe] x)
    "Stack overflow"
    Dynamische Arrays (Typ [] x) legt er anscheinend auf dem Heap ab, aber nur wenn man sie mit new erzeugt (Typ [] x = new Typ[wieviele]), ansonsten ebenfalls am Stack
    C-Arrays (Typ * x) nur mit new -> nur am Heap.
    Ich werd mir mal etwas Zeit nehmen, um mir das gründlich anzuschauen...



  • Das hört sich ja so an, als ob man auch Dinge gezielt auf dem Stack erzeugen kann. Ist das bei Objekten vielleicht auch möglich? Das würde ja heißen, dass die Diskussion oben umsonst war! 🙂 ...ein Einwand weniger gegen D! 🙂



  • Sieht seltsam aus, weil features to drpp: "Creating object instances on the stack. ..."
    😕 bin ich
    auf jedenfall kann man sich den Garbage Collector abstellen, und auch selbst bestimmen, wann er wie reinigen soll (gehört zur Standard Library)



  • hab auch mal gemessen.

    um sicherzustellen, daß er sum auch berechnet, hab ich int(sum) noch ausgegeben.

    compiliert auf msvc60, gemessen auf celeron400.

    2543
    3645

    hmm. mein rechner scheint ungefähr so schnell zu sein, wie deiner. du hast vielleicht auch nen celeron400.

    mal schauen, was java da angestellt hat.
    testhalber bau ich mal in die klasse das hier ein:

    void operator delete(void* p)
    {
    }

    2563
    371

    aha. java hat also ein wenig mehr gemacht also nix.

    mal in der main noch einfügen array[i]=0;

    2683
    441

    jo, das könnte es sein.

    als wenn java da echt noch nix gelöscht hätte.

    vielleicht bewirkt System.gc() hier noch kein echtes freigeben.

    mal nen op new bauen, der zum free paßt.

    void* operator new(size_t s)
    {
    if(free)
    {
    void* result=free;
    free=*reinterpret_cast<void**>(free);
    return result;
    }
    return ::operator new(s);
    }
    und das für c++ untypische array[i]=0; weg:

    2763
    691

    vielleicht ist es auch das, was java gemacht hat.

    public void gc()Runs the garbage collector. Calling this method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse.

    und da die letzten 3000000 allokierungen ne TestClass angelegt haben, wärs ja eine ganz logische annahme, daß die nächsten 3000000 allokierungen wieder TestClass anlegen. Und Blöcke zusammenfassen kann man immernoch, wenn andere größen angefordert werden.

    hier hab ich in c++ natürlich das problem, daß der speicher echt allokiert bleibt. und nen hintergrundprozess absetzen, der in idle-zeiten echt löscht, führt mich sofort in mehrkosten wegen multithreading und so. ihr habt das gleich dabei, was java hier recht lecker macht.

    mal nen test machen, wo die freien blöcke auch wiederverwendet werden.

    int main()
    {
      int size = 3000;
      __int64 sum = 0;
      clock_t time;
    
      time = clock();
      for(int j=0;j<3000;++j)
      {
          TestClass ** array = new TestClass* [size];
          for (int i = 0 ; i < size ; ++i)
          {
            array[i] = new TestClass(i);
          }
          for (int i = 0 ; i < size ; ++i)
          {
            sum += array[i]->getNumber ();
            delete array[i];
          }
          delete [] array;
      }
      std::cout << clock() - time<<std::endl;
      std::cout << int(sum) <<std::endl;
    
      system("PAUSE");   
      return 0;
    }
    

    17505

    uih.

    und mit selbsgebautem new und delete mit verketteter liste freier blöcke:
    741

    was macht java hier? ich nehme an, auch schnell, aber ohne, daß der user so lästige sachen wie eigenes new/delete bauen muß?



  • Original erstellt von Gregor:
    1,2 GHz P4M (bzw. 1,6 GHz, aber runtergetaktet, es lief aber auch noch was im Hintergrund. Bei beiden Programmen das gleiche, die Ergebnisse waren trotzdem reproduzierbar)

    das läßt mich befürchten, daß was an der messung nicht ok ist, denn mein celeron400 hatte fast die gleichen zeiten fürs anlegen. evtl nicht alle optimierungen beim compiler an? ka. oder die zeit geht für die RAM-Zugriffe drauf und der Prozessor dreht größtenteils Däumchen.



  • Original erstellt von volkard:
    **
    hmm. mein rechner scheint ungefähr so schnell zu sein, wie deiner. du hast vielleicht auch nen celeron400.
    **

    ...oder vielleicht ist der Flaschenhals hier ganz wo anders! 🙂 ...ich tippe auf die Speicherperformance! 🙂

    EDIT : Vielleicht sollten wir mal ein kleines Array nehmen, was in den Cache paßt und welches dann sehr oft gefüllt und wieder geleert wird.

    [ Dieser Beitrag wurde am 27.11.2002 um 00:36 Uhr von Gregor editiert. ]


Anmelden zum Antworten