Konzeptfrage: dynamischer Speicher
-
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
-
@rapso: Dieser Epic Games chief irgendwas blubb hat ja übrigens anscheinend mal einen interessanten Vortrag darüber gehalten, wie er sich eine Programmiersprache für Spieleentwickler vorstellt und den kennst du doch bestimmt. Er hat u.a. bemängelt dass heutige Programmiersprachen ein unvernünftiges Exception-Modell ("exception everywhere, everytime") haben und nicht hinreichend für Nebenläufigkeit ausgelegt sind. Du kennst doch diesen Vortrag bestimmt, was hältst du als Spieleentwickler eigentlich von seinen Aussagen? Gut, dass du "Garbage collection should be the only option" nicht gut findest, vermute ich jetzt einfach mal.
Da waren noch mehr Punkte, aber ich bin grad in der Arbeit und hab die Präsentation nicht da.
-
Optimizer schrieb:
Hmmm. Ein Grundproblem bleibt aber auch mit eigenen Allokatoren bestehen: Du machst jede Freigabe explizit.
auch ein GC muss irgendwann die trennung zwischen garbage und nicht garbage machen, das macht ein memorymanager den man selber schreibt gleich und fuer den fall optimiert, der GC macht das generisch, irgendwann und kann nicht die geschwindigkeit eines spezialisierten memorymanagers uebertreffen, denn auch ein GC hat eine memorymanager strategie, nur ist es selten die optimale die sich ein programmiere auswaehlen wuerde.
Ein gescheiter GC dagegen deallokiert nicht.
ja, wie du sagtest, er kopiert z.b. alle genutzten objekte um, also nicht nur dass er dabei jedesmal das speicherlayout aendert und somit das programm radom ist von der laufzeiteigenschaft, man zahlt die vermeitlich kuerzere allokationszeit (wenn man keinen guten allokator in c++ hat) gegen massige speicherkopiererei (natuerlich macht das ein GC nicht am stueck sondern zieht kontinuirlich zeit im hintergrund).
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.
ein GC ist schneller weil man zum vergleich immer nur die allokations und deallokationszeit nimmt, dass dafuer imens zeit fuer die verwaltung im hintergrund draufgeht, ganz zu schweigen vom manchmal doppelten speicherverbrauch wird fleissig uebergangen. ganz logisch mal verglichen:
in c++ geht ein allokator inkrementel sein budget an speicher durch und vergibt es, wenn es erreicht ist, dann wird bei jeder allokation in der freelist geschaut was der beste speicherbereich ist denn er zurueckgibt.
mit nem GC wird ebenfalls bis zum budget speicher vergeben, ist das budget erreich wird der ganze speicher zusammenkopiert, entweder in einen paralellen speicherblock (also massig memorymoves) oder der GC geht den speicher durch und versucht die luecken die da sind (dafuer muss er aufwendig evaluieren ob es ueberhaupt ne luecke ist) mit allokierten bereichen fuellen (die er ebenfalls erstmal finden muss). da ist aus meiner sicht garkeine ersparnis.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.

bei jeder version von der JVM hat sun wieder nen komplett neuen und supergeilen GC der alles vorhergewesene topt

leider sind GCs die besser sind als die speichermanager die man sonst verwendet nur marketingblub. der einzige wirkliche vorteil ist, dass man leute mit weniger plan vom coden dransetzen darf ohne angst haben zu muessen, dass sie etwas unbenutzbares erstellen. dieser sicherheitsaspekt ist aus meiner sicht ein echtes/klares Plus.
-
Optimizer schrieb:
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.

Ähhh (vorab: Ich habe nichts gegen GCs - sobald es sinnvoller ist, einen einzusetzen, tue ich das ohne Probleme) ... ein delete teilt "der Speicherverwaltung" (sei es ein GC oder etwas anderes) mit, dass dieser Speicher nicht mehr gebraucht wird.
Ohne diese "aktive Information" ist der GC darauf angewiesen, es selbst herauszufinden .... wo das per se schneller sein soll (oder durch ein mehr an Speicher ausgleichbar), ist mir schleierhaft.
Natürlich kann man direkt im delete auch die Speicherfreigabe machen, aber das wollte rüdiger mit seinem Allokator ja gerade nicht....EDIT: Hat rapso schon besser erklärt.
Gruß,
Simon2.
-
rapso schrieb:
ein GC ist schneller weil man zum vergleich immer nur die allokations und deallokationszeit nimmt, dass dafuer imens zeit fuer die verwaltung im hintergrund draufgeht, ganz zu schweigen vom manchmal doppelten speicherverbrauch wird fleissig uebergangen.
Ich muß sagen, da hast du einen ganz wichtigen Punkt angesprochen, der mir ehrlich gesagt nie richtig bewusst war. Natürlich wusste ich das das Aufräumen nur zeitlich verschoben wird, aber das es dadurch "geschönt" wird, wenn man es nicht mit in die Messung einbezieht, war mir nie bewusst. "aufgeschoben ist nicht aufgehoben" oder wie geht das Sprichwort?
-
rapso schrieb:
ja, wie du sagtest, er kopiert z.b. alle genutzten objekte um, also nicht nur dass er dabei jedesmal das speicherlayout aendert und somit das programm radom ist von der laufzeiteigenschaft, man zahlt die vermeitlich kuerzere allokationszeit (wenn man keinen guten allokator in c++ hat) gegen massige speicherkopiererei (natuerlich macht das ein GC nicht am stueck sondern zieht kontinuirlich zeit im hintergrund).
Ich denke aber schon, dass man da auch berücksichtigen muss, dass ein GC eben *nicht* mit allen Objekten etwas macht. Deshalb belegt er ja auch so viel Speicher. Er lässt 10,000 Objekte allokieren, wenn er die Collection dann macht, schiebt er nur die 100 noch lebenden rüber und mit den anderen 9900 hat er nichts gemacht. Da kannst du auch beim Deallokator noch eine ganze Menge rumtricksen, aber in jedem Fall hast du 9900 mal delete aufgerufen und *irgendwas* dabei gemacht.
denn auch ein GC hat eine memorymanager strategie, nur ist es selten die optimale die sich ein programmiere auswaehlen wuerde.
Das ist etwas, dem ich nicht wiedersprechen würde. Man nimmt sich ein "typisches" Allokationsprofil her und optimiert den GC darauf. Aber bei new und delete ist es auch nichts anderes. Wenn du nicht immensen Aufwand betreibst, deine eigenes Allokationsprofil zu bestimmen, immer up-to-date zu halten und deine Speicherverwaltung darauf anpasst, sondern wenn du standard new und delete verwendest, ist es doch vorstellbar, dass ein Standard-GC besser sein kann als das standard new und delete.
Artchi schrieb:
rapso schrieb:
ein GC ist schneller weil man zum vergleich immer nur die allokations und deallokationszeit nimmt, dass dafuer imens zeit fuer die verwaltung im hintergrund draufgeht, ganz zu schweigen vom manchmal doppelten speicherverbrauch wird fleissig uebergangen.
Ich muß sagen, da hast du einen ganz wichtigen Punkt angesprochen, der mir ehrlich gesagt nie richtig bewusst war. Natürlich wusste ich das das Aufräumen nur zeitlich verschoben wird, aber das es dadurch "geschönt" wird, wenn man es nicht mit in die Messung einbezieht, war mir nie bewusst. "was aufgeschoben ist, ist nicht aufgehoben" oder wie geht das Sprichwort?[/quote]Angesprochen aber nicht ausgeführt? Was genau bezieht man in die Messung nicht ein? Das mit dem erhöhten Speicherverbrauch ist ja kein Geheimnis - wie gesagt, man kann Speicher gegen Laufzeit tauschen und macht man auch gern.
-
Optimizer schrieb:
@rapso: Dieser Epic Games chief irgendwas blubb hat ja übrigens anscheinend mal einen interessanten Vortrag darüber gehalten, wie er sich eine Programmiersprache für Spieleentwickler vorstellt und den kennst du doch bestimmt. Er hat u.a. bemängelt dass heutige Programmiersprachen ein unvernünftiges Exception-Modell ("exception everywhere, everytime") haben und nicht hinreichend für Nebenläufigkeit ausgelegt sind. Du kennst doch diesen Vortrag bestimmt, was hältst du als Spieleentwickler eigentlich von seinen Aussagen? Gut, dass du "Garbage collection should be the only option" nicht gut findest, vermute ich jetzt einfach mal.
Da waren noch mehr Punkte, aber ich bin grad in der Arbeit und hab die Präsentation nicht da.
ja, hab mit tim mal drueber gesprochen gehabt vor ewigkeiten, die sichtweise ist halt, dass es immer mehr auf staffelungen beim programmieren gibt. auch die unreal engine bietet dazu ja extra na scriptsprache. ich kann jetzt nicht 100%ig sagen, dass es auch seine aussage ist (wie gesagt, ist schon etwas her, auch seit ich sein paper las), aber grundlegend sollte es so sein:
- unterste eben ist der Core, auch die UE3 hat einen ganz grundlegenden Core, dieser ist sowas wie ne standard lib, je nachdem sind teile in assembler, in c, in c++ oder sogar stark templatisiert geschrieben (also schon fast funktional). gecodet wird das von wirklich faehigen leuten, ich glaube bei Epic hat Tim das meiste davon gemacht, aber es gibt wohl noch ein paar die das supporten (3leute glaube ich)
- darauf setzt die engine, keine stl, boost, etc. nur mittels des cores als sprachen-lib wird entwickelt, dabei baut man auch ne VM mit jeglicher speicherverwaltung usw. das wird dann von den normalen (immer noch sehr skillten) programmierern gemacht
- darauf setzt bei epic dann der c++ gamecode auf, der leider, gerade bei externen, viel zerschiessen kann und jeder engine programmierer kennt das leid, wenn es einen absturz gibt heisst es "ist im .. modul der engine abgestuerzt, das muss R&D fixen" und dann verschwendet man zeit um rauszufinden wo die 'anwender' den fehler machten.
hier kommt nun im optimalen fall fuer spieleprogrammierer die sprache mit aller moeglichen sicherheit zum einsatz. das spart massig debuggen, weil viele dummheiten aufgrund von sprachrestriktionen erst garnicht moeglich sind.
-oberster layer ist nun die scriptsprache, sie liegt noch eins drueber und erlaubt es zur laufzeit zu coden und zur codezeit instant zu sehen was passiert.(- ok, noch ein layer drueber, hier kommt die visuelle graph-sprache die es erlaubt ohne geringste code erfahrung logik zu erstellen, perfekt fuer artists, gamedesigner usw. wenn es auch nur fuers prototyping benutzt werden wuerde).
jeder dieser layer hat seine vollste existenzberechtigung, es ist nur das image das diese sprachen so durchkreuzt. es gibt sicherlich javascript scripter die meinen dass sie ne ganze engine in JS machen koennen, gibt ja auch doom-clones die im browser laufen.
es gibt leute die meinen sie koennen alles mit C#, VB, Java. Es gibt das natuerlich auch fuer C++ oder assembler. nur ist diese fixierung total unnuetz und suboptimal. um einen weisen mann zu zittieren "the right tool for the right job"
-
Optimizer schrieb:
rapso schrieb:
ja, wie du sagtest, er kopiert z.b. alle genutzten objekte um, also nicht nur dass er dabei jedesmal das speicherlayout aendert und somit das programm radom ist von der laufzeiteigenschaft, man zahlt die vermeitlich kuerzere allokationszeit (wenn man keinen guten allokator in c++ hat) gegen massige speicherkopiererei (natuerlich macht das ein GC nicht am stueck sondern zieht kontinuirlich zeit im hintergrund).
Ich denke aber schon, dass man da auch berücksichtigen muss, dass ein GC eben *nicht* mit allen Objekten etwas macht. Deshalb belegt er ja auch so viel Speicher. Er lässt 10,000 Objekte allokieren, wenn er die Collection dann macht, schiebt er nur die 100 noch lebenden rüber und mit den anderen 9900 hat er nichts gemacht. Da kannst du auch beim Deallokator noch eine ganze Menge rumtricksen, aber in jedem Fall hast du 9900 mal delete aufgerufen und *irgendwas* dabei gemacht.
nur ist es eher andersrum, wenn du nur 100objekte hast, dann ist die wahrscheinlichkeit sehr hoch das der allokationsstack (bei c++ wie bei GC) nach oben soviel freiraum hat, dass nichts gemacht werden muss. wenn du aber dann 9900allokierte objekte hast, dann ist die wahrscheinlichkeit sehr viel groesser dass er vollaeuft und mit dieser menge an objekten hantierst du dann. das ist ja das ueble, bei nur 100allokierten objekten hat weder c++-alloc noch GC irgend ein stress.schau dir nur an was "defrag" bei windows fuer ne ewigkeit braucht um den speicher anzuordnen und ueberleg dir wieviel mehr cpu-zeit er gegenueber der festplattengeschwindigkeit hat um das optimal zu machen, bei einem GC ist cpu-time kritisch und dann muss die cpu auch noch rumkopieren, das passiert ja nicht einmal, so oft wie der c++ allokator im speicher rumspringt um ne freie stelle zu finden, so oft muss der GC speicher kopieren, anders gesagt, im kritischen bereich:
c++ brauch bei jede allokation 10zeiteinheiten
GC braucht bei jeder allokation 1zeiteinheit + alle 10allokationen 100zeiteinheiten um den speicher zu reorganisieren.natuerlich sind das rein fiktive zahlen, aber rein logisch nimmt sich keines dieser generischen mittel etwas an leistung (gemittelt).
Man nimmt sich ein "typisches" Allokationsprofil her und optimiert den GC darauf. Aber bei new und delete ist es auch nichts anderes. Wenn du nicht immensen Aufwand betreibst, deine eigenes Allokationsprofil zu bestimmen, immer up-to-date zu halten und deine Speicherverwaltung darauf anpasst, sondern wenn du standard new und delete verwendest, ist es doch vorstellbar, dass ein Standard-GC besser sein kann als das standard new und delete.
genau wie beim GC hat auch der memorymanager in c++ ein generisches system zur speicherverwaltung, es gibt keinen grund weshalb der standard-GC besser sein sollte, denn bis auf das delayed releasen koennen beide systeme die selbe strategie verfolgen um dem selben anforderungsprofil gerecht zu werden.
Artchi schrieb:
rapso schrieb:
ein GC ist schneller weil man zum vergleich immer nur die allokations und deallokationszeit nimmt, dass dafuer imens zeit fuer die verwaltung im hintergrund draufgeht, ganz zu schweigen vom manchmal doppelten speicherverbrauch wird fleissig uebergangen.
Ich muß sagen, da hast du einen ganz wichtigen Punkt angesprochen, der mir ehrlich gesagt nie richtig bewusst war. Natürlich wusste ich das das Aufräumen nur zeitlich verschoben wird, aber das es dadurch "geschönt" wird, wenn man es nicht mit in die Messung einbezieht, war mir nie bewusst. "was aufgeschoben ist, ist nicht aufgehoben" oder wie geht das Sprichwort?Angesprochen aber nicht ausgeführt? Was genau bezieht man in die Messung nicht ein? [/quote]das die allokationsschnelligkeit (und kostenlose dealokation) nur deswegen soviel schneller beim GC ist als bei C++, weil der GC dafuer im hintergrund die ganze zeit werkelt um eben diese kurzen zeiten zu ermoeglichen. du kannst in C++ sicher auch nen zweiten thread starten der dir kontinuirlich die freelist optimiert, sodass du die selben laufzeiteigenschaften hast.
-
Hmmm, das wollte ich eigentlich nicht, dass sich das hier zum Diskussionsthread zwischen GC und new/delete entwickelt. Offenbar scheinen alle mit einem der beiden wunschlos glücklich zu sein. Naja, wem trotzdem noch irgendwas zur eigentlichen Frage einfällt, nur her damit.
-
groovemaster schrieb:
Hmmm, das wollte ich eigentlich nicht, dass sich das hier zum Diskussionsthread zwischen GC und new/delete entwickelt. Offenbar scheinen alle mit einem der beiden wunschlos glücklich zu sein. Naja, wem trotzdem noch irgendwas zur eigentlichen Frage einfällt, nur her damit.
dann hast du meine Frage überlesen: Wo liegt der Sinn deiner Erweiterung? Warum sollte ich auto_ptr in die Sprache einbauen? Was kann die Erweiterung was auto_ptr nicht kann? Ist es wirklich sinnvoll eine weitere Pointer-Syntax einzuführen?
-
rüdiger schrieb:
dann hast du meine Frage überlesen: Wo liegt der Sinn deiner Erweiterung? Warum sollte ich auto_ptr in die Sprache einbauen? Was kann die Erweiterung was auto_ptr nicht kann? Ist es wirklich sinnvoll eine weitere Pointer-Syntax einzuführen?
Nein, da hast du mich vollkommen falsch verstanden. Ich habe weder gesagt, dass es eine Erweiterung zu einer Sprache sein soll. Noch habe ich gesagt, dass ich auto_ptr einbauen will. Mein Beispiel fühlt sich lediglich ähnlich an. Wenn du andere Ideen hast, kannst du sie gerne nennen. Es ging darum, wie ein High Level Konzept für dynamische Objekte aussehen könnte, fernab jeglicher Implementationen. Weder new/delete noch GC halte ich für optimal. Daher meine Frage, ob jemand einen besseren Ansatz hat.
-
Wie oft braucht man denn wirklich Speicher dynamisch mit new? Oft gehts auch ohne, wenn man nur ein bisschen plant.
-
@optimizer
http://www.st.cs.uni-sb.de/edu/seminare/2005/advanced-fp/docs/sweeny.pdf
das war glaube ich was du meintest :), auf seite 58 wird nochmal explizit gesagt, dass es soeine sprache fuer den mainstream gameprogramer geben sollte

und die stelle mit dem GC steht da wie du schon sagtest auch.
-
You got it!