Konzeptfrage: dynamischer Speicher



  • Optimizer schrieb:

    groovemaster schrieb:

    - unzureichende Effizienz
    zB wird innerhalb eines Scopes ein dynamisches Objekt angelegt
    sobald der Scope verlassen wird, soll auch dieses Objekt sterben und damit der Speicher freigegeben werden
    ein GC lässt sich hier jedoch unbestimmt viel Zeit mit der Freigabe

    Das erhöht die Effizienz. Wir reden hier ja von Speicherverwaltung, nicht von Socket-Verbindung-Verwaltung. Jedes kleine Fitzel 16B explizit in die Freispeicherliste hundertmal einzutragen anstatt 1mal 1,6 KB freizuräumen ist langsamer. Das musst du dir wirklich bewusst machen, wenn du über Speicherverwaltung nachdenkst.

    Darüber hinaus kommt hinzu, dass moderne GC-Verfahren grade bei kurzlebigen Objekten (d.h. die nur in einem engen Scope existieren) besonders effektiv sind - Stichwort Generation Scavenging. Heutzutage gibt es wirklich keinen Grund mehr, vor Garbage-Collection angst zu haben. Höchstens man ist auf Echtzeitfähigkeit angewiesen.

    tfa



  • tfa schrieb:

    Optimizer schrieb:

    groovemaster schrieb:

    - unzureichende Effizienz
    zB wird innerhalb eines Scopes ein dynamisches Objekt angelegt
    sobald der Scope verlassen wird, soll auch dieses Objekt sterben und damit der Speicher freigegeben werden
    ein GC lässt sich hier jedoch unbestimmt viel Zeit mit der Freigabe

    Das erhöht die Effizienz. Wir reden hier ja von Speicherverwaltung, nicht von Socket-Verbindung-Verwaltung. Jedes kleine Fitzel 16B explizit in die Freispeicherliste hundertmal einzutragen anstatt 1mal 1,6 KB freizuräumen ist langsamer. Das musst du dir wirklich bewusst machen, wenn du über Speicherverwaltung nachdenkst.

    Darüber hinaus kommt hinzu, dass moderne GC-Verfahren grade bei kurzlebigen Objekten (d.h. die nur in einem engen Scope existieren) besonders effektiv sind - Stichwort Generation Scavenging. Heutzutage gibt es wirklich keinen Grund mehr, vor Garbage-Collection angst zu haben. Höchstens man ist auf Echtzeitfähigkeit angewiesen.

    tfa

    wobei mir einraetsel ist warum zeugs das sowieso nur in einem bekannten scope exestiert ueberhpt in den gc kommen soll/muss.

    wie kanns performatner sein wenn ich eine komponete hab die ueber was nachdenken muss anstatt ohne nachdenken das richtige zu machen?

    und das 100x16b vs 1x1,6kb freigeben, woher weis der gc das es durchgaengige speicherbereiche sind die er einfach so als block freigeben kann?
    wurde da schon zeit vorverbraten um zu analysieren und organisieren?
    und wird diese zeit in der effizienzberechnung nicht beruecksichtigt?



  • tfa schrieb:

    Darüber hinaus kommt hinzu, dass moderne GC-Verfahren grade bei kurzlebigen Objekten (d.h. die nur in einem engen Scope existieren) besonders effektiv sind - Stichwort Generation Scavenging. Heutzutage gibt es wirklich keinen Grund mehr, vor Garbage-Collection angst zu haben.

    nur wenn man es selbst schon richtig managed, dann ist ein GC nur ueberfluessig.



  • rapso schrieb:

    tfa schrieb:

    Darüber hinaus kommt hinzu, dass moderne GC-Verfahren grade bei kurzlebigen Objekten (d.h. die nur in einem engen Scope existieren) besonders effektiv sind - Stichwort Generation Scavenging. Heutzutage gibt es wirklich keinen Grund mehr, vor Garbage-Collection angst zu haben.

    nur wenn man es selbst schon richtig managed, dann ist ein GC nur ueberfluessig.

    Managt man es denn richtig? Es ist doch grade der Vorteil, dass man mit GC sehr viel weniger selber managen muss. Die eingesparte Zeit kann man prima nutzen, um Software zu entwicklen, statt sich tagelangen Debug-Sessions hinzugeben um Speicherlecks zu finden.
    Die Performance-Einbußen durch GC sind meiner Meinung nach auch zu vernachlässigen. Die Steigerung der Entwickler-Performance allerdings ganz und gar nicht.

    tfa



  • daHa schrieb:

    wobei mir einraetsel ist warum zeugs das sowieso nur in einem bekannten scope exestiert ueberhpt in den gc kommen soll/muss.

    Soll/muss keineswegs so sein. Was ich sinnvoll auf den Stack packen kann, sollte ich da auch hintun, GC sollte IMHO kein Ersatz für Stack-Allokationen sein. Es soll ein Ersatz für new ... delete sein, für Auto-Pointer und so stuff.

    und das 100x16b vs 1x1,6kb freigeben, woher weis der gc das es durchgaengige speicherbereiche sind die er einfach so als block freigeben kann?
    wurde da schon zeit vorverbraten um zu analysieren und organisieren?
    und wird diese zeit in der effizienzberechnung nicht beruecksichtigt?

    Moderne GCs deallokieren Objekte nicht explizit und fassen dann freie Speicherblöcke zusammen. Stattdessen verschieben sie die Objekte die noch gebraucht werden in einen anderen Bereich, der Rest ist dann per Definition wieder freier Speicher. Allokieren geht dann auch deutlich schneller, weil nicht ein freier Speicherblock gesucht wird, denn der freie Speicher ist imer defragmentiert. Man erhöht genauso wie beim Stack einfach den "free space" Pointer.

    Du kannst dir mal diesen Artikel ansehen: http://msdn.microsoft.com/msdnmag/issues/1100/GCI/
    Da ist ein bisschen Wirtschaftler-Geblubber drin wie toll GC ist, aber man gewinnt einen guten Überblick darüber, wie sie funktioniert.



  • tfa schrieb:

    rapso schrieb:

    tfa schrieb:

    Darüber hinaus kommt hinzu, dass moderne GC-Verfahren grade bei kurzlebigen Objekten (d.h. die nur in einem engen Scope existieren) besonders effektiv sind - Stichwort Generation Scavenging. Heutzutage gibt es wirklich keinen Grund mehr, vor Garbage-Collection angst zu haben.

    nur wenn man es selbst schon richtig managed, dann ist ein GC nur ueberfluessig.

    Managt man es denn richtig? Es ist doch grade der Vorteil, dass man mit GC sehr viel weniger selber managen muss. Die eingesparte Zeit kann man prima nutzen, um Software zu entwicklen, statt sich tagelangen Debug-Sessions hinzugeben um Speicherlecks zu finden.
    Die Performance-Einbußen durch GC sind meiner Meinung nach auch zu vernachlässigen. Die Steigerung der Entwickler-Performance allerdings ganz und gar nicht.

    tfa

    rapso meint sowas, worauf du nicht eingehst:

    void foo()
    {
       std::string str;
    }
    

    Wo muß ich da mehr managen und nachdenken, als wenn ich einen GC hätte? Genau das mache ich, wenn ich ein Objekte anlege, das nur in einem Scope Gültigkeit haben soll. In DEM Fall, ist ein GC in keiner Weise hilfreicher. Und der GC räumt mein str-Objekt auch nicht schneller auf, als wenn der Compiler nur den Stackpointer hoch oder runter zählt.

    Klar, wenn ich mit new etwas anlege, halt dynamisch (worum es hier in dem Thread auch geht!!!), kann mir ein GC Zeit beim Entwickeln einsparen. Richtig. Aber das werden wir in C++ auch ab 2009 laut neuen Standard machen können. Da es in diesem Thread aber laut groovemaster nicht speziell um C++ geht, ist das eigentlich auch nebensächlich.



  • Wie fordert der string gleich nochmal intern seinen Speicher an? Oha, dynamisch...



  • Ja und? Was hab ich als Programmierer damit zutun? Ich habe schliesslich auf tfa's Beitrag geantwortet. Dem es rein um den Aufwand für den Programmierer ging: "ohne GC viel mehr Tipparbeit und mehr nachdenken, wenn ich Scopeobjekte habe"... was aber falsch ist. Egal was der String intern macht.

    Und falls es um Performance geht: wie kann ein GC generell schneller sein als ein new/delete? Notfalls nimm ich SmartHeap dazu. was aber auch beweist, das ein Heap-Management nur "schlau" implementiert sein muß. Völlig unabhängig ob ich einen GC nehme oder eine Library wie SmartHeap. Ein GC ist schliesslich keine Zauberei, oder doch? Und weiterhin: auch ei GC kann schlecht implemntiert und designed sein. Wer garantiert mir, wenn ich einen GC nehme, das ich auch Perfomancevorteile bekomme? Rein Zufällig mögen die GC von MS gut sein, aber die SUN Java-GC ist z.B. schlechter als der von anderen Java-Implementierern. Auch wenn ich das Weltbild einiger SUN-Fans damit zerstöre...

    Artchi

    PS: Mist, ich habe jetzt Java mit ins Spiel gebracht. Das wird mir jetzt zum Verhängnis! 😃



  • Ein GC ist schon nett, da man beim selbst Managen schnell Fehler einhandeln kann. Wobei man zu den Geschwindigkeitsvorteilen die Optimizer aufgezählt hat aber sagen muss, dass dies oft nur die Frage des Allokators/Deallokators ist. Man kann ja auch einen Allokator/Deallokator schreiben, der wie ein moderner GC funktioniert. Der Deallokator sagt einfach nur "der Speicher hier ist zwar noch reserviert aber eigentlich frei" und der Allokator durchsucht diese Liste bevor er neuen Speicher anlegt (oder so ähnlich).

    groovemaster schrieb:

    Ihr seht schon, es ist also eine Art in die Sprache integrierter auto_ptr.

    wozu sollte man auto_ptr in die Sprache integrieren, wenn man es genauso gut als Template-Klasse schreiben kann, wie es bisher ist?



  • wozu sollte man auto_ptr in die Sprache integrieren, wenn man es genauso gut als Template-Klasse schreiben kann, wie es bisher ist?

    Das Argument vieler ist halt, das alles Buildin sein muß. Egal ob es Sinn macht oder nicht. Genau das werden wir aber in Zukunft in C++ weniger sehen, laut C++ Komitee. Mehr über Libraries und Templates, in die C++-Core nur noch das nötigste.



  • Artchi schrieb:

    auch ei GC kann schlecht implemntiert und designed sein. Wer garantiert mir, wenn ich einen GC nehme, das ich auch Perfomancevorteile bekomme? Rein Zufällig mögen die GC von MS gut sein, aber die SUN Java-GC ist z.B. schlechter als der von anderen Java-Implementierern. Auch wenn ich das Weltbild einiger SUN-Fans damit zerstöre...

    Einen schlechten GC kann man ja leicht ersetzen (also leicht im Sinne von ich nehme einen besseren GC und packe den dazu und entferne den schlechten, nicht leicht im Sinne von ich schreib mir mal eben einen guten GC ;)). Die manuelle Verwaltung zu ändern dürfte deutlich schwieriger sein



  • Ja, worum geht es denn nun? Um die Manuelle Verwaltung vs. Automatische Verwaltung? Oder um Performance? 😉

    Wenn es um Performance geht (GC soll schneller sein), sage ich, dann kann ich einfach die Standardlibrary durch eine bessere tauschen (z.B. die SmartHeap nutzt). Hab ich also auch einen Austausch vorgenommen. Muß ich zwar neu kompilieren, interessiert aber den Endanwender nicht, welche Lib ich nutze. Hauptsache das Ding rennt.

    Wenn es um den Programmierer geht: spielt das "Austauschen können" des GCs keine Rolle. Entweder ich nimm einen GC oder nicht. Beides kann ich heute machen. Ich kann es manuell machen, ich kann Smartpointer nehmen, oder ich nehme einen GC. Und ab 2009 haben wir eh offiziell einen GC im ISO-C++. Die Diskussion werden wir ab dann hoffentlich hier nicht mehr haben.



  • rüdiger schrieb:

    Wobei man zu den Geschwindigkeitsvorteilen die Optimizer aufgezählt hat aber sagen muss, dass dies oft nur die Frage des Allokators/Deallokators ist. Man kann ja auch einen Allokator/Deallokator schreiben, der wie ein moderner GC funktioniert. Der Deallokator sagt einfach nur "der Speicher hier ist zwar noch reserviert aber eigentlich frei" und der Allokator durchsucht diese Liste bevor er neuen Speicher anlegt (oder so ähnlich).

    Hmmm. Ein Grundproblem bleibt aber auch mit eigenen Allokatoren bestehen: Du machst jede Freigabe explizit. Der Allokator kann das natürlich ansammeln und dann größere Bereiche auf einmal freigeben, aber *irgendetwas* machst du immer beim Deallokieren. Ein gescheiter GC dagegen deallokiert nicht.

    Artchi schrieb:

    Und falls es um Performance geht: wie kann ein GC generell schneller sein als ein new/delete?

    IEs ist in der Praxis wirklich oft so (ich sag jetzt mal absichtlich nicht "meistens"). Das hat viele Gründe, new muss freien Speicher suchen, delete muss ausgeführt werden (ein guter GC macht kein delete), Speicher kann fragmentieren und schlechte Lokalität haben, es gibt hunderte Gründe, warum ein GC schneller oder langsamer ist. Du wirst natürlich trotzdem immer was konstruieren können, wo eine klassische Heap-Verwaltung geiler ist. In der Praxis ist er aber oft schneller. Ein eigener Allokator kann wieder noch besser sein, aber darauf hast du doch auch eher selten Lust.

    aber die SUN Java-GC ist z.B. schlechter als der von anderen Java-Implementierern

    Der ist wirklich grottig, hat Pause-Times im Zehntelsekunden-Bereich, da schaudert's mich echt. Die, die am meisten rumlabern, bauen echt den schlechtesten. 🙂



  • Artchi schrieb:

    Und ab 2009 haben wir eh offiziell einen GC im ISO-C++. Die Diskussion werden wir ab dann hoffentlich hier nicht mehr haben.

    Was glaubst du, wie die dann erst losgeht. 😃 "soll ich ihn verwenden oder nicht?"



  • GCs sind doch im Prinzip schneller, weil sie Arbeit verschieben können und weil sie leicht den Heap aufräumen können. Aber das ist auch mit anderen Allokatoren möglich.

    @Optimizer
    dieses irgend was ist aber vermutlich nicht der Rede wert. Wenn doch, dann kann man bei der manuellen Verwaltung die Freigabe ja einfach auf einen günstigeren Zeitpunkt verlegen. (So wie man den meisten GCs ja auch sagen kann "Nerv getz nich!" ;))

    Artchi schrieb:

    Ja, worum geht es denn nun? Um die Manuelle Verwaltung vs. Automatische Verwaltung? Oder um Performance? 😉

    Wenn es um Performance geht (GC soll schneller sein), sage ich, dann kann ich einfach die Standardlibrary durch eine bessere tauschen (z.B. die SmartHeap nutzt). Hab ich also auch einen Austausch vorgenommen. Muß ich zwar neu kompilieren, interessiert aber den Endanwender nicht, welche Lib ich nutze. Hauptsache das Ding rennt.

    Bei manueller Verwaltung kannst du natürlich die Allokatoren austauschen, aber du kannst nicht einfach die interne Verwaltung umstricken. Das wollte ich eigentlich sagen. Man kann ja teilweise die GCs sogar vor dem starten einer Anwendung wählen.



  • rüdiger schrieb:

    Wenn doch, dann kann man bei der manuellen Verwaltung die Freigabe ja einfach auf einen günstigeren Zeitpunkt verlegen.

    Dann ist dieses Vormerken dieses etwas und spätestens das kannste nicht verlegen. Wie ich sagte, man kann die Deallokationen ansammeln und wird sicherlich auch gemacht. Am Ende steht man aber immer 2 Nachteilen da:
    - man muss beim delete *irgendwas* machen
    - man muss freie Speicherbereiche wieder zusammenfassen
    Man hat viel rumgeforscht an manueller Speicherverwaltung, schon länger als an GCs und da gibt es alle möglichen Tricks. <Troll>Deshalb ist sie überhaupt noch gerade so konkurrenzfähig. 😃 </Troll>

    Der GC hat natürlich auch Arbeit die manuelle Speicherverwaltung nicht hat, zum Beispiel Referenzen ändern und Write-Barriers implementieren. Scheint aber durchaus sehr tragbar zu sein. Vor allem aber kann ich beim GC nahezu beliebig mehr Laufzeit einsparen und dafür mehr Speicher verbrauchen, also eintauschen, das ist schon sehr nett.



  • tfa schrieb:

    rapso schrieb:

    tfa schrieb:

    Darüber hinaus kommt hinzu, dass moderne GC-Verfahren grade bei kurzlebigen Objekten (d.h. die nur in einem engen Scope existieren) besonders effektiv sind - Stichwort Generation Scavenging. Heutzutage gibt es wirklich keinen Grund mehr, vor Garbage-Collection angst zu haben.

    nur wenn man es selbst schon richtig managed, dann ist ein GC nur ueberfluessig.

    Managt man es denn richtig?

    Die meisten scheinen dazu unfaehig zu sein. Leuten die soeinen anschein machen empfehle ich auch aus voller ueberzeugung auf Java/C#/VB zu setzen.

    Es ist doch grade der Vorteil, dass man mit GC sehr viel weniger selber managen muss.

    alles hat seinen preis, lange ladezeiten, suboptimale leistung, massig speicherverschwendung, einmal laenger nachdenken oder immer diese kosten in kauf nehmen... aber vielen faellt das garnicht mehr auf, leider.

    Die eingesparte Zeit kann man prima nutzen, um Software zu entwicklen, statt sich tagelangen Debug-Sessions hinzugeben um Speicherlecks zu finden.

    wenn man kontrolle abgibt, hat man weniger ahnung was passiert und dadurch kommen erst die langen debugsessions. es waere unsinnig zu glauben, dass nur weil ein objekt "garbage" ist statt deletet zu werden, dass man sich nicht um sein ableben kuemmern muss, denn resourcenfreigabe usw. muss dann immer noch gemacht werden, was viele programmierer von sprachen mit GC absolut nicht drauf haben ala "das liegt am GC, mein program hat kein Leak, das kann garnicht sein, das passiert nur in C++."

    Die Performance-Einbußen durch GC sind meiner Meinung nach auch zu vernachlässigen.

    ich finde den imensen speicheranstieg von manchmal 10fach gegenueber dem vorher existierendem tool in anderen sprachen nicht vernachlaessigbar. die manchmal langen ladezeiten bei denen man sich wundert, ob das OS den doppelklick realisiert hat und die starke traegheit der anwendungen sehr uebel.

    Die Steigerung der Entwickler-Performance allerdings ganz und gar nicht.

    die entwicklungsgeschwindigkeit ist nicht trvial zu messen. jemand der mit C# anfaengt ist zu anfang sicherlich viel schneller als jemand der in assembler schreibt, aber sobald man seine sprache beherrscht ist die entwicklungsgeschwindigkeit von jedem individuell und nicht sonderlich von der highlevel-sprache abhaengig, vor allem wenn man sein Hirn oefter trainiert und nicht auf vorgefertigtes setzt, kann mann bessere leistung bringen... ist wie mit dem kopfrechnen.



  • Optimizer schrieb:

    rüdiger schrieb:

    Wenn doch, dann kann man bei der manuellen Verwaltung die Freigabe ja einfach auf einen günstigeren Zeitpunkt verlegen.

    Dann ist dieses Vormerken dieses etwas und spätestens das kannste nicht verlegen. Wie ich sagte, man kann die Deallokationen ansammeln und wird sicherlich auch gemacht. Am Ende steht man aber immer 2 Nachteilen da:
    - man muss beim delete *irgendwas* machen
    - man muss freie Speicherbereiche wieder zusammenfassen
    Man hat viel rumgeforscht an manueller Speicherverwaltung, schon länger als an GCs und da gibt es alle möglichen Tricks. <Troll>Deshalb ist sie überhaupt noch gerade so konkurrenzfähig. 😃 </Troll>

    Aber der GC kann auch irgend wann seine Runde fahren und dann kostet es mich mehr als das bisschen was ein delete macht <gegentroll>und bei den meisten Sprachen die einen GC haben dürfte fast jede Operation teurer sein, als das delete meines vorgeschlagenen Allokators in C++ :p </gegentroll>



  • rüdiger schrieb:

    Aber der GC kann auch irgend wann seine Runde fahren und dann kostet es mich mehr als das bisschen was ein delete macht

    Das ist exakt das, was wir noch rausfinden müssen. Da ich Speicherbedarf gegen Laufzeit eintauschen kann, verlierst du auf jeden Fall schon mal, wenn es Hart auf Hart kommt. Für nen vernünftigen Speicherverbrauch hilft jetzt wohl nur, wenn jeder an seines glaubt (ich messe zum Beispiel 0.3 % der Laufzeit im GC, bietest du weniger in new/delete) oder wir battlen uns jetzt mit nicht-repräsentativen Benchmarks. 😃 👍



  • Bei manueller Verwaltung kannst du natürlich die Allokatoren austauschen, aber du kannst nicht einfach die interne Verwaltung umstricken.

    Was meinst du damit genau? Das die Objekte nicht hin und her geschoben werden können, ist klar. Aber auch dieser Vorgang müsste eigentlich in dem Moment Performance kosten?

    Ansonst hier ein paar Infos zum SmartHeap-Design (bei dem man übrigens seinen Code nicht nachtäglich ändern muß):
    http://www.microquill.com/smartheap/sh_tspec.htm#2.2


Anmelden zum Antworten