Benutzer mit den meisten Antworten
Speicherung von Instanzen von Klassen

Frage
-
abstract class Material { public abstract MaterialType GetMaterialType(); } class Wood : Material { public override MaterialType GetMaterialType() { return MaterialType.Wood; } }
class Stone : Material
{
public override MaterialType GetMaterialType()
{
return MaterialType.Stone;
}
}enum MaterialType { Wood, Stone
};
Jetzt erstelle ich eine Variable vom Typ Material, und initialisiere sie mit "new Wood()".
Wenn ich jetzt "GetMaterialType" aufrufe, wie erkennt der Computer dass er "GetMaterialType" der Wood Klasse aufrufen muss und nicht zB von der Stone Klasse?
Allgemein, wie speichert er Instanzen von Klassen, brauchen Klassen mehr Speicher weil sie zB noch eine Erkennungs-ID oder sowas in der Art haben?
Sry für die vielen Fragen, findet man aber leider in keinem Buch...
Ich freue mich auf Antworten
- Bearbeitet _Homer_Simpson_ Sonntag, 24. Juni 2012 13:17
Antworten
-
Hallo,
in dem Artikel Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects findest Du in dem Abschnitt
MethodTable eine Grafik die zeigt, wie die .NET Laufzeit (CLR) die Informationen zu einem Typen verwaltet.
Dazu ist in jeder Klasse (und Schnittstelle) am Anfang eine Adresse auf die Methodentabelle hinterlegt -
dazu kommt der sog. SyncBlock der für das Sperren von Instanzen via lock verwendet wird
(mehr dazu bei Interesse: Safe Thread Synchronization)Über die Methodentabelle kann die Laufzeit die virtuellen Aufrufe durchführen.
Wobei dies nicht immer passieren muss. Wenn der Just-in-Time Compiler erkennen kann,
welcher Typ und damit welche Methode aufgerufen wird,
so kann der virtuellen Aufruf in einen konventionellen Aufruf umgewandelt werden.
Sehr kleine Methoden (wie die in Deinem Beispiel) können inline kompiliert werden,
d. h. die Anweisungen werden ohne zusätzlichen Aufruf ausgeführt.
Das bläht zwar etwas den Maschinencode auf, hat aber bei heutigen Prozessoren den Vorteil,
dass die Instruktionen dicht beieinander und im Cache liegen können.Weitere detaillierte Informationen enthält der anfangs genannte Artikel.
Gruß Elmar
- Als Antwort markiert _Homer_Simpson_ Sonntag, 24. Juni 2012 13:41
-
Hallo,
grundsätzlich sind die virtuellen Aufrufe in Deinem Szenario kaum der Problemverursacher.
Große mehrdimensionale Arrays können schon eher "fordernd" werden.
Anstatt mit [100, 100, 100] einen großen Speicherblock anzufordern,
könnte ein verzweigtes (jagged) Array günstiger.
Damit kannst Du leichter eine "virtuelle" Speicherverwaltung implementieren,
die nur jeweils aktive Blöcke im Speicher lädt und den Rest verzögert oder auch wieder rauswirft.Einige Interna zu Arrays in .NET findest Du unter: Arrays UNDOCUMENTED
Nachtrag: Zur Performance von virtuellen Aufrufen siehe Appendix: Cost of Virtual Calls and Allocations>
Wobei das aus den Anfangszeiten vn .'NET stammt und dort die letzten Jahre weiter optimiert wurde,
vor allem auch im Jitter, siehe vorherige Antwort.Gruß Elmar
- Bearbeitet Elmar BoyeEditor Sonntag, 24. Juni 2012 14:11 Nachtrag
- Als Antwort markiert _Homer_Simpson_ Sonntag, 24. Juni 2012 14:44
Alle Antworten
-
Hallo,
Erstmal muss die Material-Klasse abstract sein, da sie sonst keine abstrakten Member enthalten kann! Weiterhin initialisierst du die Instanz von Material ja z.B. mit Stone. Da die Methode abstract ist, muss es also im Kind der Mutterklasse sein, die in deinem Fall Stone ist, da Sie damit initialsiert wurde. Also wird bei Aufruf von
GetMaterialType()
auch Stone zurück geliefert. Da es aus der Stone-Klasseninstanz aufgerufen wird.
Wenn eine Klasse eine "Erkennungs-ID" hat brauch Sie natürlich mehr RAM, z.B. 4Byte für ein Int32 als ID-Typ. Ansich verwaltet die CLR von .NET die ganzen Klasseninstanzen und du brauchst dich in der Regel nicht zu kümmern wo was liegt. Du kannst natürlich GetGashCode() überschreiben und damit ggf. die Instanzen vergleichen. Aber wirklich benötigt habe ich solche Erkennungs-ID's nur einmal bei einer rießigen Liste an Dynamisch hinzugefügten Controls zu einer Liste und da auch nur um besser mit den Events zurecht zu kommen.
"Sry für die vielen Fragen, findet man aber leider in keinem Buch..."
dafür gibts doch Foren ;)
Koopakiller - http://koopakiller.ko.ohost.de/
-
Erstmal danke für die Antwort.
Das hatte ich gefragt weil ich mit einem Programm Performanceprobleme habe und nicht so recht weiß, woran es liegt.
Um genau zu sein, es soll ein Minecraft ähnliches Spiel werden, also eine Welt aus Blöcken in der man bauen kann.
Bei Minecraft werden die Blöcke so gespeichert, dass es ein Array aus BlockIDs gibt, und die Blöcke sind statische Klassen. Dadurch wird vieles komplizierter, weshalb ich es so gemacht hab, dass es nur ein Array aus Blöcken gibt, in welches eben Blöcke gespeichert werden welche von der abstrakten Block Klasse abgeleitet sind...
Kann es also sein, dass die Aufrufe so lange dauern, da der Computer erstmal ermitteln muss welche von "Block" abgeleitete Klasse jetzt an der Stelle ist um dann die funktion derer Klasse aufzurufen?
Ich hab schon alles mit DateTime.Now vorher und nachher auf die Zeit geprüft die es jeweils braucht und das war gerade das verdächtigste...
Hoffe man kann es einigermaßen verstehen
hier nochmal der Grund für meine Vermutung:
DateTime x1 = DateTime.Now; BlockType[,,] blockTypes = new BlockType[100, 100, 100]; DateTime x2 = DateTime.Now;
for (int x = 0; x < 100; x++) { for (int y = 0; y < 100; y++) { for (int z = 0; z < 100; z++) { blockTypes[x, y, z] = testchunk.GetBlockType(new IntVector3(x, y, z)); } } } DateTime x3 = DateTime.Now;
setze ich einen Haltepunkt direkt nach "DateTime x3 = DateTime.Now;" sieht man an x1-3 die Zeiten zu dem Zeitpunkt.
das reservieren der 4MByte dauert genau 2 Millisekunden;
die Schleife läuft in 4 Millisekunden durch (ohne den aufruf in der Schleife);
wenn ich "blockTypes[x, y, z] = BlockType.Stone" in der Schleife benötigt sie insgesamt 20 Millisekunden;
mit aufruf benötigt sie 120 Millisekunden! Das ist fast eine Achtelsekunde!
- Bearbeitet _Homer_Simpson_ Sonntag, 24. Juni 2012 13:31
-
Hallo,
in dem Artikel Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects findest Du in dem Abschnitt
MethodTable eine Grafik die zeigt, wie die .NET Laufzeit (CLR) die Informationen zu einem Typen verwaltet.
Dazu ist in jeder Klasse (und Schnittstelle) am Anfang eine Adresse auf die Methodentabelle hinterlegt -
dazu kommt der sog. SyncBlock der für das Sperren von Instanzen via lock verwendet wird
(mehr dazu bei Interesse: Safe Thread Synchronization)Über die Methodentabelle kann die Laufzeit die virtuellen Aufrufe durchführen.
Wobei dies nicht immer passieren muss. Wenn der Just-in-Time Compiler erkennen kann,
welcher Typ und damit welche Methode aufgerufen wird,
so kann der virtuellen Aufruf in einen konventionellen Aufruf umgewandelt werden.
Sehr kleine Methoden (wie die in Deinem Beispiel) können inline kompiliert werden,
d. h. die Anweisungen werden ohne zusätzlichen Aufruf ausgeführt.
Das bläht zwar etwas den Maschinencode auf, hat aber bei heutigen Prozessoren den Vorteil,
dass die Instruktionen dicht beieinander und im Cache liegen können.Weitere detaillierte Informationen enthält der anfangs genannte Artikel.
Gruß Elmar
- Als Antwort markiert _Homer_Simpson_ Sonntag, 24. Juni 2012 13:41
-
Gut, allgemein kenne ich mich mit MC recht gut aus.
Lädtst du schon die Grafiken o.ä.? Daran könnte es z.B. liegen, wenn du das nicht Assynchron machst. So würde ich es amchen wie MC, die Mappe in 16*16 Block große Chunks aufgliedern und die dann jeweils ein 3 Dimensionales Array enthalten lassen. Versuche mal die "Chunks" Asynchron zu laden, dann wird das sicherlich schneller. Allgemein würde ich bei Spielen aber mehr auch DirectX odr OpenGL setzen, da die dann auch mit der Grafik schneller zurecht kommen, da Sie fast ausschlöießlich die GPU fordern nicht die CPU.
Ansich sollte man beachten das ein normaler MC Chunk mit 16*16*256 Blöcken insgesammt 65536 Blöcke enthält, was für einen PC schon mal relativ viel ist. Davon dann um die 100 Stück, dann ist man bei 6,5 Millionen. Das es da performance Probleme gibt kann ich mir schon vorstellen. Ich weiß ja nicht was die Klassen mit den Materialien schon alles können, aber um so mehr, desto mehr wird es "hängen". MC lastet 4 Kerne á 3,4 GHz aus, dein Programm kann das sicherlich auch bald.
Koopakiller - http://koopakiller.ko.ohost.de/
-
@Koopakiller
es enthält momentan erst einen einzigen chunk, hat aber bereits bei 32*32*32 (das entspricht 16*16*128) nurnoch 10 FPS...
das hat 2 Gründe:
1. die Kollisionsabfrage vom Spieler, welche ich noch nicht optimiert habe. zudem fragt sie die boundingBoxes ebenfalls so ab wie in dem letzten codeblock...
2. die Draw Methode, welche ebenfalls den letzten codeBlock in ähnlicher weise enthält... Die Grafiken hab ich auch noch einzeln, wodurch die Textur bei jedem Block neu an die Grafinkkarte gesendet werden muss, dadurch dass ich die in eine einzelne packe sollte es etwas schneller gehn
deshalb wollte ich das erstmal klären
Und Minecraft ist in JAVA programmiert, welches ein Interpreter ist...
@Elmar Danke, das wars was ich gesucht habe
PS: C# und inline? soweit ich weiß gibts da keine möglichkeit
- Bearbeitet _Homer_Simpson_ Sonntag, 24. Juni 2012 14:04
-
Hallo,
grundsätzlich sind die virtuellen Aufrufe in Deinem Szenario kaum der Problemverursacher.
Große mehrdimensionale Arrays können schon eher "fordernd" werden.
Anstatt mit [100, 100, 100] einen großen Speicherblock anzufordern,
könnte ein verzweigtes (jagged) Array günstiger.
Damit kannst Du leichter eine "virtuelle" Speicherverwaltung implementieren,
die nur jeweils aktive Blöcke im Speicher lädt und den Rest verzögert oder auch wieder rauswirft.Einige Interna zu Arrays in .NET findest Du unter: Arrays UNDOCUMENTED
Nachtrag: Zur Performance von virtuellen Aufrufen siehe Appendix: Cost of Virtual Calls and Allocations>
Wobei das aus den Anfangszeiten vn .'NET stammt und dort die letzten Jahre weiter optimiert wurde,
vor allem auch im Jitter, siehe vorherige Antwort.Gruß Elmar
- Bearbeitet Elmar BoyeEditor Sonntag, 24. Juni 2012 14:11 Nachtrag
- Als Antwort markiert _Homer_Simpson_ Sonntag, 24. Juni 2012 14:44
-
thx nochmal,
ich überlege auch ob ich auf C++ umsteige, DirectX ist da zwar viel komplizierter (als XNA in C#), aber ich glaube das lohnt sich.
Außerdem könnte ich auch mal alle call by value in call by reference ändern, wird ja dadurch schneller sein dass es keine Werte kopieren muss, muss man aber auch verdammt aufpassen dass man die Werte dann nicht versehentlich mal ändert...
Danke nochmal an für die Antworten
-
Hi,
ich überlege auch ob ich auf C++ umsteige
und was erhoffst Du dir davon? C++ ist kein Allheilmittel für Performanceprobleme oder ähnliches. Wenn man von falschen Voraussetzungen ausgeht, Logikfehler im Programm hat, sprachspezifische Gegebenheiten nicht berücksichtigt, ... wird man bei allen Sprachen/Technologien auf Probleme stoßen.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Hallo,
Tipp von einem "alten Hasen" - der C++ und Assembler neben einem anderen Dutzend Sprachen programmiert hat -
an den Neueinsteiger:
Mit .NET kann man einen Großteil aller Probleme in einem Bruchteil der Zeit lösen,
die paar Stellen, bei denen C++ (und DirectX pur im Vergleich zu XNA) Vorteile bringen,
setzen voraus, dass man das Problem als solches identifiziert hat.Löse das Problem in der jetzigen Umgebung.
Das Schwierigste ist i. a. herauszufinden, wo die Wurzel des Problem steckt.
Und soweit ich die Diskussion beurteilen kann, bist Du noch nicht dort angekommen.Um "Profi" in gleich welcher Umgebung zu werden, braucht es Monate und Jahre.
Wechselst Du die Pferde, verbringst Du die Zeit mit dem Erlernen der Syntax
und den Besonderheiten einer anderen Sprache und (unmanaged = ungesicherten) Umgebung.
Der Lösung des Problems bringt es Dich aber nicht näher.
Umgekehrt gilt: Hast Du das Problem in .NET "geknackt",
kannst Du das Wissen auch in andere Umgebungen übertragen.Nicht zuletzt: Überbewerte die Performance am Anfang nicht, schon Donald Knuth schrieb:
Premature optimization is the root of all evil (or at least most of it) in programming.Besser ist es Du strebst eine sauber und klare Umsetzung an.
Darauf aufbauend könntest Du Dich z. B. mit den Async Möglichkeiten von .NET 4.5
auseinandersetzen und so versuchen Deine Cores besser auszulasten.
Gruß Elmar