vorteile einer virtual machine?
-
frenki schrieb:
Du brauchst sowieso alle Plattformen, für die du dein Programm rausgibst. Oder willst du mir erzählen, das du ein Programm, das du meinetwegen in Java unter Linux entwickelt hast einfach so für Windows freigibst, ohne es jemals getesetet zu haben?
ich kenn jemand der hat 'ne ziemlich fette anwendung in java unter windoofs gecodet. mit allem schnickschnack wie datenbankanbindung an'ne db2, client-zu-client kommunikation, client-server über's internet usw. bei der inbetriebnahme unter linux musste nur _eine_ programmzeile geändert werden (irgendwas mit der gui sah nicht so schick aus). ich schätze mal so easy geht portieren nur mit java
-
Hi
Nativ compiler für java gibts doch.
Java und .Net haben zumindest für BWL er den Vorteil, das da die sachen wie GC, Reflaction, GUI, Netzwer, ... bereits bestandteil der sprache sind. Andersrum müsste man sich das ja alles zukaufen oder seber entwickeln. Stichpunkt kosten und fehler.
Auserdem haben diese sprachen Marketingtechnische vorteile. Wenn jemand frägt ob man auch linux einsetzen könnte kann er antworten "kein problem wir setzen auf java. das läuft auf allen gängigen platformen."
Arber mir stellt sich gertade die Frage "Compile once, run anyware" hat ja mit java seine berechtigung. Die java vom gibts ja von sun für einige platformen.
Nur bei .Net frag ich mich was da eine VM Sinnmacht. Die gibts ja von MS ja nur für ihre eigenen Betriebsysteme. (Mono mal nicht betrachtet da nicht von MS) Oder ist das MS neue schnittstelle zum System? und sie haben das nur als VM entwickelt, damit die Leute sich drann gewöhnen können, wenn im nachfolger von longhorn z.B nur noch diese schnitstelle zur verfügung steht.
gruss
-
- Ich kann prozessorspezifisch optimieren.
- Compile once, run anywhere gewinnt heute an Bedeutung durch verschiedene Prozessorarchitekturen. Überlegt mal:
IA64, x86_64 und x86 mal Windows, Linux gibt schon mal 6 verschiedene Kombinationen.
- Sicherheit: Ich kann ein und das selbe Programm mit verschiedenen Sicherheitseinstellungen laufen lassen, ohne es dauernd überwachen zu müssen. Ich muss nicht bei jeder Anforderung nach einem Socket-Handle prüfen, ob das Programm das darf. Stattdessen start ich das Programm mit "no sockets!" und der JIT-Compiler pflanzt dann im native Code überall SecurityExceptions rein.
- Ich kann Code flexibler gestalten. Klassen dynamisch zur Laufzeit hinzuladen. Runtime-Reflection. Das sind Dinge, die immer mehr an Bedeutung gewinnen. Diese Flexibilität krieg ich ohne JIT-Compilierung fast nicht hin.
-
Termite schrieb:
Nur bei .Net frag ich mich was da eine VM Sinnmacht. Die gibts ja von MS ja nur für ihre eigenen Betriebsysteme. (Mono mal nicht betrachtet da nicht von MS) Oder ist das MS neue schnittstelle zum System? und sie haben das nur als VM entwickelt, damit die Leute sich drann gewöhnen können, wenn im nachfolger von longhorn z.B nur noch diese schnitstelle zur verfügung steht.
Hem, du hast dich eben gerade unglaubwürdig gemacht. Warum muß die .NET VM von MS kommen?
Das will mir nicht in mein Gehirn rein. C# und das .NET Baseframework sind in der ECMA zertifiziert: ein freier Standard, und somit kann und SOLL nicht nur MS die VM und das Framework auf anderen Plattformen implementieren. Ist also wie mit C++: jeder darf .NET implementieren. (nur WindowsForms und ein paar andere .NET-Teile sind nicht in der ECMA)
Bei Java ist das nicht so. Darfs nur deine JavaVM auch JavaVM nennen, wenn du ordentlich Kohle an SUN abgedrückt hast.
-
BWL-Manager schrieb:
Dazu kommt, daß C++ bei den Führungskräften in dem Ruf steht schwer zu sein und Java/C# leichter zu sein.
Nicht nur bei "Führungskräften"
-
Artchi schrieb:
Bei Java ist das nicht so. Darfs nur deine JavaVM auch JavaVM nennen, wenn du ordentlich Kohle an SUN abgedrückt hast.
Sicher? Eclipse und JBuilder haben schon mal ihren eigenen Compiler und IBM ne eigene VM (1.4 glaub ich) und ich kann mir nicht so wirklich vorstellen, dass die dafür zahlen mussten.
Letztlich gibt es auch eine öffentlich einsehbare JVM specification.
-
Optimizer schrieb:
- Ich kann prozessorspezifisch optimieren.
- Compile once, run anywhere gewinnt heute an Bedeutung durch verschiedene Prozessorarchitekturen. Überlegt mal:
IA64, x86_64 und x86 mal Windows, Linux gibt schon mal 6 verschiedene Kombinationen.eine VM muss auch für diese Plattformen irgendwie entwickelt und kompiliert werden. Und es gibt ja genug gute Compiler für diese Plattformen. Und wenn ich für den Kunden für jede Plattform eine Binärversion anbiete, was hat man da für einen Nachteil?
Optimizer schrieb:
- Sicherheit: Ich kann ein und das selbe Programm mit verschiedenen Sicherheitseinstellungen laufen lassen, ohne es dauernd überwachen zu müssen. Ich muss nicht bei jeder Anforderung nach einem Socket-Handle prüfen, ob das Programm das darf. Stattdessen start ich das Programm mit "no sockets!" und der JIT-Compiler pflanzt dann im native Code überall SecurityExceptions rein.
ja ok, aber wieso wird dafür dieser Bytecode benötigt? Man könnte doch auch den bereits vorhandenen native code mit SecurityExceptions versehen.
Optimizer schrieb:
- Ich kann Code flexibler gestalten. Klassen dynamisch zur Laufzeit hinzuladen. Runtime-Reflection. Das sind Dinge, die immer mehr an Bedeutung gewinnen. Diese Flexibilität krieg ich ohne JIT-Compilierung fast nicht hin.
Dieser ganzer "Schnickschnack" kann doch auch im native Code gemacht werden.
Klassen, die dynamisch nachgeladen werden sollen, könnten z.B. in dynamische Bibliotheken, wie DLLs, ausgelagert werden. Man bräuchte eine standardisierte Schnittstelle dafür.
-
@mathik: Warum schwer, wenn es auch einfacher geht? Bei der Entwicklung VM ist jemand anderes verantwortlich. Du sparst jede Menge Zeit und kosten.
Bei den anderen Punkten das selbe. Warum das Rad neu erfinden und viel Geld in die Entwciklung stecken?
Im Buiness läuft es halt immer nach dem selben Schema: Man muss den breakeven zwischen Kosten und Nutzen finden. Genau diesen Punkt haben Sun und MS erkannt. Eine VM erleichtert dem Programmierer die Arbeit ungemein.
-
mathik schrieb:
eine VM muss auch für diese Plattformen irgendwie entwickelt und kompiliert werden. Und es gibt ja genug gute Compiler für diese Plattformen. Und wenn ich für den Kunden für jede Plattform eine Binärversion anbiete, was hat man da für einen Nachteil?
n gewisser zeitaufwand wenn du updates für 20 plattformen erstellen musst
-
BWL-Manager schrieb:
@mathik: Warum schwer, wenn es auch einfacher geht? Bei der Entwicklung VM ist jemand anderes verantwortlich. Du sparst jede Menge Zeit und kosten.
Bei den anderen Punkten das selbe. Warum das Rad neu erfinden und viel Geld in die Entwciklung stecken?
Im Buiness läuft es halt immer nach dem selben Schema: Man muss den breakeven zwischen Kosten und Nutzen finden. Genau diesen Punkt haben Sun und MS erkannt. Eine VM erleichtert dem Programmierer die Arbeit ungemein.
ich bechaupte doch nicht, dass man das alles selber machen sollte, weil es dann viel besser ist. Ich finde sogar Java toll, weil diese Sprache eine solche umfangreiche Bibliothek hat, GC und Reflection anbietet. Ich würde sie allerdings noch toller finden, wenn Java-Programme auch ohne die VM laufen würden, und somit schnellere Startzeiten (Wegfall von JIT) und weniger Speicher fressen würden.
-
Vorteile einer virtuellen Maschine:
Plattformunabhängigkeit: Programme für eine virtuelle Maschine laufen auf allen realen Maschinen, für die die virtuelle Maschine implementiert ist. Sie kann dadurch Architekturtransparenz schaffen.
dynamische Optimierung ist möglich
-
Wollte ich Dir auch nicht unterstellen. Aber gerade eine VM macht es einem so einfach(s. Optimizer's Beispiele).
Die langen Ladezeiten stören primär auch nur bei Desktopanwendungen. Ich pers. mag allerdings auch Binärcode lieber, aber man macht das was der Arbeitgeber möchte.
-
mathik schrieb:
Optimizer schrieb:
- Ich kann prozessorspezifisch optimieren.
- Compile once, run anywhere gewinnt heute an Bedeutung durch verschiedene Prozessorarchitekturen. Überlegt mal:
IA64, x86_64 und x86 mal Windows, Linux gibt schon mal 6 verschiedene Kombinationen.eine VM muss auch für diese Plattformen irgendwie entwickelt und kompiliert werden. Und es gibt ja genug gute Compiler für diese Plattformen. Und wenn ich für den Kunden für jede Plattform eine Binärversion anbiete, was hat man da für einen Nachteil?
Ich habs doch grad aufgezählt, dass du gut und gerne auf 6 Versionen kommen kannst. Und es ist auch nicht völlig ausgeschlossen, wenn auch nicht das größte Problem, dass du vielleicht mal ein Problem mit einer von den 6 Versionen hast, was du sonst nicht hast.
Optimizer schrieb:
- Sicherheit: Ich kann ein und das selbe Programm mit verschiedenen Sicherheitseinstellungen laufen lassen, ohne es dauernd überwachen zu müssen. Ich muss nicht bei jeder Anforderung nach einem Socket-Handle prüfen, ob das Programm das darf. Stattdessen start ich das Programm mit "no sockets!" und der JIT-Compiler pflanzt dann im native Code überall SecurityExceptions rein.
ja ok, aber wieso wird dafür dieser Bytecode benötigt? Man könnte doch auch den bereits vorhandenen native code mit SecurityExceptions versehen.
Es geht darum, das Programm mit verschiedenen Einstellungen zu starten und du kannst den native Code nicht dynamisch anpassen. Lies es bitte nochmal.
Optimizer schrieb:
- Ich kann Code flexibler gestalten. Klassen dynamisch zur Laufzeit hinzuladen. Runtime-Reflection. Das sind Dinge, die immer mehr an Bedeutung gewinnen. Diese Flexibilität krieg ich ohne JIT-Compilierung fast nicht hin.
Dieser ganzer "Schnickschnack" kann doch auch im native Code gemacht werden.
Klassen, die dynamisch nachgeladen werden sollen, könnten z.B. in dynamische Bibliotheken, wie DLLs, ausgelagert werden. Man bräuchte eine standardisierte Schnittstelle dafür.Nein, in dem Maße, wie es mit Java und .Net möglich ist, kriegst du das nicht mal annähernd hin. Ich sag nur: Runtime-Reflection. Ohne VM verflucht schwer und dynamisch Klassen hinzuzuladen, wie willst du das bitte bei native code machen? Ja, du brauchst ne standardisierte Schnittstelle dafür, *thumbs up*. Da bin ich gespannt, wie die aussehen soll. Vergiss es, fast nicht tragbarer Aufwand.
JIT-compilierter Code ist von Natur aus flexibler, das kannst du nicht wegdiskutieren. Du kannst für dich entscheiden ob du das willst und brauchst, aber dein fest kompilierter Native Code ist faktisch nicht so flexibel.
-
Hi
Artchi schrieb:
...
Hem, du hast dich eben gerade unglaubwürdig gemacht. Warum muß die .NET VM von MS kommen?Das will mir nicht in mein Gehirn rein. C# und das .NET Baseframework sind in der ECMA zertifiziert: ein freier Standard, und somit kann und SOLL nicht nur MS die VM und das Framework auf anderen Plattformen implementieren. Ist also wie mit C++: jeder darf .NET implementieren. (nur WindowsForms und ein paar andere .NET-Teile sind nicht in der ECMA)
...
ich geb zu ich hab noch nichts mit .Net gemacht. ich weis nur das es ein Basisframework von MS gibt und das für linux MONO entwickelt wird. Soweit ich das mal mitbekommen hat war MS federführen am .Net beteiligt. bzw hat das dan versucht es als standard festschreiben zu lassen. Mit mal wieder so schöhnen ausnahmen das ms sachen nur bei ms laufen und wo anders nicht.
Ich hab das gefühl MS den Standard nur als Alibi und wegen des Marketings gemacht hat.
Wer würde auf .Net umsteigen, wenn nur MS Compiler und Framework liefern dürfte? Und man dafür auch noch bezahlen müsste. ist ja dan so ähnlich wie mit Delphi von Borland.[EDIT]
Weiter Vorteil für VMs. sie lassen sich ja unabhängig von der Anwendung warten. Somit kann auch eine Anwendung noch mit sicherheit patchen versorgt werden obwohl die Anwendung gar nicht mehr weiterentwickelt wird. ( sun hate ja mal nen fehler in der JRE 1.4.? ) währen das jetzt alles Nativ drin, hätte der Anwender nicht mal ne nöglichkeit so ein sicherheitsloch zu stopfen. Woher weis er was du verwendet hast, woher soll er das nötige update bekommen.gruss
-
Ein echter Vorteil (zumindest von .net) ist ein vereinheitlichtes Klassenmodell zwischen verschidenen Sprachen (habe ich gerade "C DLLs in VB" gehört? *graus*). Das hat zwar primär nichts mit der VM zu tun, ist aber doch ein nettes Feature. Wenn .NET nur ein *wirklich* offener Standard wäre, ohne das MS wegen Sachen wie Mono mit den Patent - Ketten rasselt ...
-
Optimizer schrieb:
mathik schrieb:
Dieser ganzer "Schnickschnack" kann doch auch im native Code gemacht werden.
Klassen, die dynamisch nachgeladen werden sollen, könnten z.B. in dynamische Bibliotheken, wie DLLs, ausgelagert werden. Man bräuchte eine standardisierte Schnittstelle dafür.Nein, in dem Maße, wie es mit Java und .Net möglich ist, kriegst du das nicht mal annähernd hin. Ich sag nur: Runtime-Reflection. Ohne VM verflucht schwer und dynamisch Klassen hinzuzuladen, wie willst du das bitte bei native code machen? Ja, du brauchst ne standardisierte Schnittstelle dafür, *thumbs up*. Da bin ich gespannt, wie die aussehen soll. Vergiss es, fast nicht tragbarer Aufwand.
JIT-compilierter Code ist von Natur aus flexibler, das kannst du nicht wegdiskutieren. Du kannst für dich entscheiden ob du das willst und brauchst, aber dein fest kompilierter Native Code ist faktisch nicht so flexibel.Ich hab mal nach Reflection gesucht, da ich nicht in Java eingearbeitet bin und bin auf folgenden Link gestossen:
http://java.sun.com/docs/books/tutorial/reflect/
(Fals dieser Link nicht das beschreibt was du unter Runtime-Reflection verstehst dann entschuldige ich mich im Voraus)Ich seh da nichts was übermässig schwer mit nativ Code zu machen wäre, natürlich nur mit ein wenig Unterstüzung des Compilers und kompatiblen ABIs.
* Determine the class of an object.
typeid & dynamic_cast
* Get information about a class's modifiers, fields, methods, constructors, and superclasses
* Find out what constants and method declarations belong to an interface.Kann der Compiler alles in den VTable packen.
* Create an instance of a class whose name is not known until runtime.
Das Factory Pattern unter der Compilerhaube.
* Get and set the value of an object's field, even if the field name is unknown to your program until runtime.
Offset und Type kann im VTable nachgeschlagen werden wenn der Compiler diese Information da reintut.
* Invoke a method on an object, even if the method is not known until runtime.
Kann man auch noch im Vtable nachschlagen. Alles was man braucht ist eine Map die den Funktionsnamen mit dem Funktionspointer assoziiert.
Hier kann man allerdings auch noch ein wenig optimiren indem man, nachdem man das erste mal den Namen nachgeschlagen hat, den Funktionsaufruf während der Laufzeit überschreiben um dann nächstes mal direkt die richtige Funktion aufzurufen. Der Compiler muss nur genügend NOPs während der Übersetzung reinpacken damit keine Sprünge durcheinander kommen. Wenn die Anzahl der Parameter bekannt ist, ist das auch kein Problem. Fals die Anzahl nicht bekannt ist kann man ein Arraypointer übergeben.
* Create a new array, whose size and component type are not known until runtime, and then modify the array's components.
Das ginge indem man std::vector von einer abstrakten Basisklasse erben lassen würde und in jeden VTable eine Funktion hinzufügen würde die ein std::vector für diese Klasse erstellt.
Jetzt mal ganz davon abgesehen, dass ich das meiste eher als Spielerei einstuffe als wirklich nützlich, ist nichts davon ohne VM unmöglisch oder wirklich schwerer als eine Implementirung ohne VM. Vieles würde ich sogar schwieriger mit einer VM die den Code in nativ Code übersetzt finden.
Der angebliche Vorteil der Anpssungfähigkeit des Bytecodes hink auch, denn wer hat gesagt, dass man dafür eine VM braucht? Man kann den Bytecode doch einfach in einem Installationsprogram in nativ Code übersetzen. Sehr ähnlich wird das doch schon heute mit sehr vielen open source Programmen gemacht, nur eben dass hier der Sourcecode zur Verfügung steht und kein Bytecode.
Weiter Vorteil für VMs. sie lassen sich ja unabhängig von der Anwendung warten. Somit kann auch eine Anwendung noch mit sicherheit patchen versorgt werden obwohl die Anwendung gar nicht mehr weiterentwickelt wird. ( sun hate ja mal nen fehler in der JRE 1.4.? ) währen das jetzt alles Nativ drin, hätte der Anwender nicht mal ne nöglichkeit so ein sicherheitsloch zu stopfen. Woher weis er was du verwendet hast, woher soll er das nötige update bekommen.
DLLs kann man auch austauschen, das heist Fehler in einer Biblothek können auch behoben werden. Ein Program in einer VM laufen zu lassen nur weil dem Compiler vielleicht ein Übersetzungsfehler unterläuft ist zwar ein Vorteil, allerings ein sehr schwacher Vorteil der Nachteile wie längere Ladezeit im Normalfall nicht aufwiegt.
Die hauptsächlichen Vorteile einer VM sind die gleichen wie die von jedem Interpreter. Der Code muss nicht installiert werden und kann daher sofort nachdem er zur Verfügung steht benutzt werden, sprich der Vorteil liegt bei vernetzten Rechnern von unterschiedlicher Platform die Code austauschen. Bei Desktoprechnern beschränkt das sich zum größten Teil auf Applets, Javascript und Ähnliches.
Man beachte bitte, dass viele Vorteile von Java Programmen weder etwas mit Java ansich, noch irgendetwas mit einer VM (wobei letzteres oft sogar ein Nachteil ist) zu tun haben. Java hat eine breitgefecherte Standard Bibliotek und wird auch ansonsten viel von Größen der IT Welt wie Sun gefördert. Das sind die wahren Vorteile von Java. Das gleiche gilt natürlich auch für .net.
Genau sowenig ist die Tatsache, dass viele Daus wahrscheinlich make als sehr schwer zu bedienen empfinden, ein teschniches Problem sondern eines einer bestimmten Implementirung. Hätte make ein GUI Interface wie viele Windows Installer, was teschnisch überhaupt kein Problem ist, würde das bereits viel bringen.
Desweiteren sind auch Portirungsproblem von C/C++ Programmen von Platform zu Platform oder Compiler zu Compiler ein Nachteil gegenüber Java allerdings kein Nachteil gegenüber einer VM. Wenn jede Java VM ihre eigenen Erweiterungen und ihre eigenen Biblioteken hätte dann würden, trotz VM, die gleichen Probleme herschen wie derzeit in der C/C++ Welt.
Viele Sprachen die eine VM haben Vorteile allerdings diese sind in der Regel nicht auf die VM zurück zu führen.
-
Ben04 schrieb:
Ich seh da nichts was übermässig schwer mit nativ Code zu machen wäre, natürlich nur mit ein wenig Unterstüzung des Compilers und kompatiblen ABIs.
* Determine the class of an object.
typeid & dynamic_cast
Das ist keine Reflection. Das Programm kennt natürlich seine Klassen, da ist nichts tolles dran. Interessant wird's erst, wenn du dynamisch Klassen hinzulädst. Ich kann z.B. ne IDE schreiben und dafür ne Plugin-Schnittstelle anbieten.
Ich les dann alle .class-Dateien in meinem plugins-Verzeichnis aus, die jeder Programmier nachträglich durch einfaches reinkopieren verändern oder hinzufügen kann. Für jedes Plugin erstelle ich einen Menüeintrag, nimm alle öffentlichen Methoden als Untermenü her und ruf sie nur noch auf, wenn der User den Eintrag auswählt.
Also (Pseudocode):Bestimme Dateinamen aller .class Dateien ladeKlase(dateiname) Alle öffentlichen Methoden getten erstelle dafür menüeinträge, die bewirken: invoke(methode)
Du kannst jetzt natürlich auch dein eigenes Format für Plugins entwerfen. Kannst irgendne config-Datei auslesen und dynamisch auf irgendwelche C-Funktionen in einer beiliegenden DLL linken. Dann hast du genau für diesen speziellen Anwendungsfall eine Lösung, die definitiv weniger schön ist.
* Get information about a class's modifiers, fields, methods, constructors, and superclasses
* Find out what constants and method declarations belong to an interface.Kann der Compiler alles in den VTable packen.
Genau, für Klassen, die er kennt, kann er das tun. Aber nicht für Klassen, die erst zur Laufzeit hinzugeladen werden.
* Create an instance of a class whose name is not known until runtime.
Das Factory Pattern unter der Compilerhaube.
Höh? Du weißt doch zur Compilierzeit noch nicht mal, was die Klasse des zu erstellenden Objekts für Konstruktoren hat. Da bin ich ja mal gespannt. Wie du ohne JIT-Compilierung dann noch eine Factory erstellen kannst.
* Get and set the value of an object's field, even if the field name is unknown to your program until runtime.
Offset und Type kann im VTable nachgeschlagen werden wenn der Compiler diese Information da reintut.
Was für ne VTable? Es gibt keine VTable für Klassen, die du nicht compilierst. Und zur Laufzeit kriegst du die Infos nicht mehr, außer du kannst zur Laufzeit noch was reincompilieren -> JIT-compilierung
* Invoke a method on an object, even if the method is not known until runtime.
Kann man auch noch im Vtable nachschlagen. Alles was man braucht ist eine Map die den Funktionsnamen mit dem Funktionspointer assoziiert.
Wie gesagt - es gibt keine VTable.
Hier kann man allerdings auch noch ein wenig optimiren indem man, nachdem man das erste mal den Namen nachgeschlagen hat, den Funktionsaufruf während der Laufzeit überschreiben um dann nächstes mal direkt die richtige Funktion aufzurufen. Der Compiler muss nur genügend NOPs während der Übersetzung reinpacken damit keine Sprünge durcheinander kommen. Wenn die Anzahl der Parameter bekannt ist, ist das auch kein Problem. Fals die Anzahl nicht bekannt ist kann man ein Arraypointer übergeben.
Wie, wo was? Der Compiler kann zur Laufzeit in deinem Fall nichts mehr machen. Du kannst nur Methoden aufrufen
- deren Name du zur Compilierzeit kennst
- deren Signatur du zur Compilierzeit kennst* Create a new array, whose size and component type are not known until runtime, and then modify the array's components.
Das ginge indem man std::vector von einer abstrakten Basisklasse erben lassen würde und in jeden VTable eine Funktion hinzufügen würde die ein std::vector für diese Klasse erstellt.
Auch wenn der Elementtyp und -größe erstmal zur Compilierzeit unbekannt ist? Ne. Wie willst du das machen? Du weißt ja noch nicht mal, ob dein dynamisch hinzugeladener Typ einen Standardkonstruktor hat.
Ich glaube, du hast nicht ganz bedacht, was Laufzeit-Reflection bedeutet. Du hast erstmal keine VTable und kannst sie erst zur Laufzeit erstellen, weil du vorher die Klassendefinition nicht hast. Du brauchst immer irgendein für deine Fälle angepasstes Format, oder von mir aus auch eins, was sehr flexibel ist, aber trotzdem wirst du nicht Klassen von anderen einfach reinladen können, wenn die anderen UND du dafür nicht spezielle Dinge vereinbaren.
btw. jetzt einen nativen JIT-Compiler schreiben zählt jetzt nicht.
-
Ben04 schrieb:
Man beachte bitte, dass viele Vorteile von Java Programmen weder etwas mit Java ansich, noch irgendetwas mit einer VM (wobei letzteres oft sogar ein Nachteil ist) zu tun haben. Java hat eine breitgefecherte Standard Bibliotek und wird auch ansonsten viel von Größen der IT Welt wie Sun gefördert. Das sind die wahren Vorteile von Java. Das gleiche gilt natürlich auch für .net.
...
Desweiteren sind auch Portirungsproblem von C/C++ Programmen von Platform zu Platform oder Compiler zu Compiler ein Nachteil gegenüber Java allerdings kein Nachteil gegenüber einer VM. Wenn jede Java VM ihre eigenen Erweiterungen und ihre eigenen Biblioteken hätte dann würden, trotz VM, die gleichen Probleme herschen wie derzeit in der C/C++ Welt.Viele Sprachen die eine VM haben Vorteile allerdings diese sind in der Regel nicht auf die VM zurück zu führen.
Genau auf den Punkt gebracht. Das ist genau das, was ich meine!
@Optimizer
ich kann nicht nachvollziehen, warum man für Laufzeit-Reflection eine VM braucht. Man könnte auch jede Klasse native in eine .class Datei mit den ganzen Reflection-Informationen (wie Funktionssignaturen, Konstruktoren, etc.) packen. Dann generiert halt der Compiler für jede Klasse eine getClass():Class Methode. Diese Class hat dann die ganzen Reflection-Informationen, die man in Java auch hat. Dann kannste auch "ladeKlasse(dateiname)" aufrufen und mit den ganzen gettern die Informationen aus der .class Datei holen. (öffnet mal mit einem Editor eine .class Datei!)In C++ ist (Laufzeit)-Reflection deswegen schwierig zu realisieren, weil es hierfür einfach keine Compiler-Unterstützung und keinen Standard fürs dynamische Laden gibt.
Ich bin ehrlich gesagt immer noch nicht von den Vorteilen einer VM überzeugt worden (außer bei den Server- und Applet-Geschichten). Der ganze andere Schnickschnack (Reflection, "SecurityExceptions") könnte meiner Meinung nach auch ohne eine VM realisiert werden.
Ich programmiere gerne in Java, weil es dort einfach eine geile Bibliothek für fast alles gibt.
Allerdings finde ich, dass Java noch erfolgreicher wäre, wenn es dort keine VM gäbe, weil dadurch die Anwendungen viel Speicher fressen und lange Startzeiten durch JIT haben. Die ganzen "Wartungssachen" sind für mich auch wirklich kein Argument. Ich denke jeder Anbieter kann es in Kauf nehmen, für jede Plattform eine native Version zu kompilieren (nicht neu zu schreiben!).
-
mathik schrieb:
@Optimizer
ich kann nicht nachvollziehen, warum man für Laufzeit-Reflection eine VM braucht. Man könnte auch jede Klasse native in eine .class Datei mit den ganzen Reflection-Informationen (wie Funktionssignaturen, Konstruktoren, etc.) packen.Tut mir leid, wenn ich etwas blöd frage: Was ist eine native .class - Datei? Ist das Teil ausführbar? Wenn ja, dann ist es ja fein, und ich muss es nicht mehr zur Laufzeit compilieren. Enthält es alle Reflection-Informationen, die ich brauche? Fein.
Dann generiert halt der Compiler für jede Klasse eine getClass():Class Methode. Diese Class hat dann die ganzen Reflection-Informationen, die man in Java auch hat. Dann kannste auch "ladeKlasse(dateiname)" aufrufen und mit den ganzen gettern die Informationen aus der .class Datei holen. (öffnet mal mit einem Editor eine .class Datei!)
Bedenke dies:
class Base { virtual void methode() = 0; }; int main() { Base* x; cout << "Welche Klasse möchten Sie hinzuladen?"; Class MyDerived; cin >> MyDerived; x = new MyDerived(); // Ich sag jetzt mal, das hat nen Standard-Konstruktor x->methode(); }
Oh verdammt. Das wird jetzt schwierig. Also das MyDerived hast du nicht zur Verfügung, während du main() compilierst. Mit irgendwelchen krassen Datenstrukturen kriegst du das vielleicht noch hin, die Methode dynamisch richtig zu binden. Aber das ist ja nicht das Ende der Fahnenstange.
Jetzt kann ich noch ein paar weitere Klassen hinzuladen. Jedesmal ändert sich die ganze dynamische Bindung. Das x->methode(); kann nach jedem hinzuladen einen anderen Effekt haben. Jedesmal muss sich das Verhalten von dynamic_cast und typeid() ändern. Und das Ganze ohne Neucompilierung des Hauptprogramms. Selbst wenn du das noch sauber hinkriegst, bist du jetzt schon um Längen inperformanter als Java, was einfach neu compiliert und immer noch völlig simpel dynamisch bindet. Und jetzt gehen die Probleme erst los.
Jetzt schaut dann die .class Datei so aus:
class Derived : Base { void foo(); };
Und ich stelle fest, ja, die implementiert gar nicht meine abstrakte Methode. Das gibt Ärger. Du hast keine Möglichkeit, dass zur Kompilierzeit festzustellen, musst jetzt in dein Programm also nen halben Compiler einbauen, um zur Laufzeit festzustellen, ob das dann überhaupt geht. Damit ist es schon fraglich, ob du dich jetzt überhaupt an meine kleine Einschränkung gehalten hast, die da lautete, keine JIT-Compiler in das Programm einzubauen.
Das Ganze kann noch unendlich viel komplizierter werden, wenn Mehrfachvererbung hinzukommt. Vergiss auch nicht, dass du durch das hinzuladen neuer Klassen, vorhandenen, eigentlich statischen Code ändern musst.
class Fraction { // Implementiert nicht op<< aber ein op(double) }; int main() { Type type; ... // Klasse Fraction laden Type* a new Type(5, 2); cout << *a; // Gibt ein double aus. }
Ich darf aber statt Fraction auch was anderes laden, oder?
Jetzt laden wir die Klasse Fraction2 hinzu, die den op<< aber implementiert.
Jetzt muss statt dem op(double) der op<< aufgerufen werden, der nicht mal Element der Klasse selber ist, sondern global.
Was wir jetzt haben ist keine dynamische Bindung, auch keine "extended super complicated dynamische Bindung", sondern völlig anderes Verhalten. Und das machst du mir ohne Compiler.Ne, ich bin ja eigentlich schon fast geneigt zu sagen, dass die Sprache C++ schon an sich fast zu kompliziert für solche Späße ist. Aber dann ohne JIT-Compiler noch... kann ich mir nicht vorstellen.
In C++ ist (Laufzeit)-Reflection deswegen schwierig zu realisieren, weil es hierfür einfach keine Compiler-Unterstützung und keinen Standard fürs dynamische Laden gibt.
Rate mal, wieso.
Ich bin ehrlich gesagt immer noch nicht von den Vorteilen einer VM überzeugt worden (außer bei den Server- und Applet-Geschichten). Der ganze andere Schnickschnack (Reflection, "SecurityExceptions") könnte meiner Meinung nach auch ohne eine VM realisiert werden.
Kann jeder zu stehen wie er will. Ich sehe in einer VM viele Vorteile und Nachteile, die allesamt im Laufe der Zeit behoben werden könnten. Ist aber nicht meine Absicht, dich zu überzeugen. Ich will dir nur zeigen, dass es Dinge gibt, die ohne VM nicht gehen, was ja der Topic war.
Ich programmiere gerne in Java, weil es dort einfach eine geile Bibliothek für fast alles gibt.
Allerdings finde ich, dass Java noch erfolgreicher wäre, wenn es dort keine VM gäbe, weil dadurch die Anwendungen viel Speicher fressen und lange Startzeiten durch JIT haben.Vielleicht bist du noch nicht tief genug in Java eingestiegen. Ein paar wirklich geile Features, wegen den unter anderem Java so geschätzt wird, sind ohne VM nicht möglich. Das geht schon los beim dynamischen Laden von Datenbank-Treibern *an mein Praktikum mit Schaudern denk*.
Du musst Java so nehmen wie es ist und ich finde es gut so.
-
Optimizer schrieb:
Kann der Compiler alles in den VTable packen.
Genau, für Klassen, die er kennt, kann er das tun. Aber nicht für Klassen, die erst zur Laufzeit hinzugeladen werden.[/quote]
Und die DLL wurde etwa nicht von Compiler übersetzt? Es ist ja nicht so, dass alle VTables in der exe Datei liegen müssen.Optimizer schrieb:
Höh? Du weißt doch zur Compilierzeit noch nicht mal, was die Klasse des zu erstellenden Objekts für Konstruktoren hat. Da bin ich ja mal gespannt. Wie du ohne JIT-Compilierung dann noch eine Factory erstellen kannst.
Für jede Klasse generiert der Compiler eine Funktion die eine Instance dieser Klasse erstellt. Nun legt er eine Map die den Namen der Klasse mit der Funktion assoziirt. Wenn du nun eine Dll lädst hat diese auch so eine Map. Während des Laden müssen sie nur zusammen gefügt werden.
Optimizer schrieb:
Hier kann man allerdings auch noch ein wenig optimiren indem man, nachdem man das erste mal den Namen nachgeschlagen hat, den Funktionsaufruf während der Laufzeit überschreiben um dann nächstes mal direkt die richtige Funktion aufzurufen. Der Compiler muss nur genügend NOPs während der Übersetzung reinpacken damit keine Sprünge durcheinander kommen. Wenn die Anzahl der Parameter bekannt ist, ist das auch kein Problem. Fals die Anzahl nicht bekannt ist kann man ein Arraypointer übergeben.
Wie, wo was? Der Compiler kann zur Laufzeit in deinem Fall nichts mehr machen. Du kannst nur Methoden aufrufen
- deren Name du zur Compilierzeit kennst
- deren Signatur du zur Compilierzeit kennstWer sagt, dass nur der Compiler ist der Code schreibt? Das Program kann ja selber an sich umschreiben.
In etwa so hatte ich mir das vorgestellt (Pseudo ASM)
loopup_name: pop eax ;Schlag Funktions Pointer nach und pack ihn in eax ;Generire den Code um die Funktion in eax aufzurufen und speicher ihn in eax pop ebx mov [ebx] eax pop eax ;füll alles von [eax] bis [ebx] mit NOPs auf jmp ebx ;Irgendwo im Code schreib_von: push schreib_bis push schreib_von push name jmp lookup_name nop nop schreib_bis:
Natürlich muss hierführ das Program schreibenden Zugriff auf seinen Code haben. Wenn das nicht der Fall ist, bleibt noch die Möglichkeit einen statischen Funktionspointer einzusetzen. Der Compiler setzt ihn auf loopup_name und diese Funktion setzt ihn dann auf etwas anderes. Da der Aufruf ja über einen Funktionspointer stattfindet kann man den Aufruf jeder Zeit woanders enden lassen.
Optimizer schrieb:
Du hast erstmal keine VTable und kannst sie erst zur Laufzeit erstellen, weil du vorher die Klassendefinition nicht hast. Du brauchst immer irgendein für deine Fälle angepasstes Format, oder von mir aus auch eins, was sehr flexibel ist, aber trotzdem wirst du nicht Klassen von anderen einfach reinladen können, wenn die anderen UND du dafür nicht spezielle Dinge vereinbaren.
Da bin ich ganz deiner Meinung, allerdings wie bereits gesagt kann man auch VTables aus einer DLL nachladen und in eine VTable kann sämtliche Informationen über einen Type speichern die bei der Übersetzung bekannt sind.
mathik schrieb:
Die ganzen "Wartungssachen" sind für mich auch wirklich kein Argument. Ich denke jeder Anbieter kann es in Kauf nehmen, für jede Plattform eine native Version zu kompilieren (nicht neu zu schreiben!).
Mit make ähnlichen Tools muss der Anbieter noch nicht mal nativ Versionen anbieten. Man müsste sich auf eine einheitlich Sprache einigen in der man Anwendungen verbreitet, das kann auch soetwas wie Java Bytecode. Dann stellt jedes OS ein Tool zur Verfügung mit der man den Code in nativ Code übersetzt und ganz nebenbei das Program auch noch installiert. Man hat somit sämtliche Vorteile der Wartbarkeit jedoch keine Nachteile der VM. Daus werden sich die Funktionsweise die heutigen Windows Installationsprogrammen ähnelt mit Sicherheit freuen. Man muss ihnen ja nicht sagen, dass der Compiler läuft, also machen sie sich auch keinen Kopf dadrüber
.
Optimizer schrieb:
class Base { virtual void methode() = 0; }; int main() { Base* x; cout << "Welche Klasse möchten Sie hinzuladen?"; Class MyDerived; cin >> MyDerived; x = new MyDerived(); // Ich sag jetzt mal, das hat nen Standard-Konstruktor x->methode(); }
Oh verdammt. Das wird jetzt schwierig. Also das MyDerived hast du nicht zur Verfügung, während du main() compilierst. Mit irgendwelchen krassen Datenstrukturen kriegst du das vielleicht noch hin, die Methode dynamisch richtig zu binden. Aber das ist ja nicht das Ende der Fahnenstange.
Also ich sehe die Schwierigkeit nicht? Wie bereits oben gesagt braucht der Compiler nur eine map<string, void*(*)(...)> in die EXE und in die DLL zu packen. Beim laden der Dll werden dann beide zusammen gefügt. Dann muss der Compiler aus
x = new MyDerived();
nur ein
x = constructor_map["MyDerived"];
machen. Vielleicht noch ein paar Tests machen, wie zum Beispiel ob so eine Klasse geladen ist und ob sie auch von Base erbt und dann wenn nötig eine Exception werfen.
Das einzige was nicht geht ist eine dynamisch hinzugeladene Klasse auf den Stack zu packen. Aber wofür gibt es std::auto_ptr? Einfach unter die Compilerhaube und der Programmierer wird es nie merken. MS macht das auch so in C++/CLI.
Allerdings frag ich mich wirklich wo du soetwas brauchen willst? Jedes Pluginsystem ist anders und ich kann mir nicht vorstellen, dass du mit einem so allgemeinem Anstatz glücklich wirst.
Optimizer schrieb:
Jetzt kann ich noch ein paar weitere Klassen hinzuladen. Jedesmal ändert sich die ganze dynamische Bindung. Das x->methode(); kann nach jedem hinzuladen einen anderen Effekt haben. Jedesmal muss sich das Verhalten von dynamic_cast und typeid() ändern.
Alte Klasse aus der Map rauswerfen und neue hinzufügen. dynamic_cast mit Hilfe einer virtuellen is_castable(type_info&) Methode implementiren. typeid spiegelt nur Laufzeit Informationen. Allerdings wenn du soetwas brauchst musst du nur eine zweite Map anlegen und dann nach gleichen Schema vorgehen wie um ich es bei der Erschaffung der einer Instance gezeigt habe.
Optimizer schrieb:
Und das Ganze ohne Neucompilierung des Hauptprogramms.
Würd ich auch nicht wollen. Wenn man erst am Code rumschreiben geht, dann wird es erst kompliziert. Ist aber alles machbar.
Optimizer schrieb:
Selbst wenn du das noch sauber hinkriegst, bist du jetzt schon um Längen inperformanter als Java, was einfach neu compiliert und immer noch völlig simpel dynamisch bindet. Und jetzt gehen die Probleme erst los.
Ich sehe nicht wieso das mit einer VM so performant sein soll. Das Nachschlagen in einer Map ist nicht langsam und wie oben gezeigt muss man es ja nur einmal tun. Unter Java ist das ja auch nicht kostenlos, der Code muss neu überstetz werden und wenn man dann noch optimiert sind das zwar einmalige Kosten aber sehr große in der das gesamte Program einfriert. Oder willst du das ganze threadsafe machen? Also in dem einen Thread läuft der Compiler und in einem anderen wird auf Eingaben des Users reagiert. Und was ist mit Instancen von Klassen die es nach dem neu kompilieren gar nicht mehr gibt? Was mit Funktionspointern (wenn es sowas in Java gibt) die nun ins Leere zeigen? Also ich glaub nicht, dass das so einfach geht wie du dier das vorstellst. Bitte um Aufklärung.
Optimizer schrieb:
class Fraction { // Implementiert nicht op<< aber ein op(double) }; int main() { Type type; ... // Klasse Fraction laden Type* a new Type(5, 2); cout << *a; // Gibt ein double aus. }
Ich gehe mal davon aus, dass dieses "Type" eigentlich ein "Fraction" sein soll und zwischen "a" und "new" noch ein "=" gehört.
Optimizer schrieb:
Ich darf aber statt Fraction auch was anderes laden, oder?
Jetzt laden wir die Klasse Fraction2 hinzu, die den op<< aber implementiert.
Jetzt muss statt dem op(double) der op<< aufgerufen werden, der nicht mal Element der Klasse selber ist, sondern global.
Was wir jetzt haben ist keine dynamische Bindung, auch keine "extended super complicated dynamische Bindung", sondern völlig anderes Verhalten. Und das machst du mir ohne Compiler.Das Zauberwort heist double Dispatching. Und man kann jeden buildin Operator auch durch einen Funktionsaufruf ersetzen.
Sebst Templates kannst mit einer nachgeladenen Klasse spezialisieren. Man braucht zunächst wieder eine Map die den Namen der Klasse als Schlüssel hat. Jetzt schlägt man einen Klassen VTable mit sämtlichen Methoden der Klasse nach. Alles was kein Operator muss wieder in einer weiteren Map nachgeschlagen werden. So nun spezialisert der Compiler während des Übersetzen für einen Type der alle Methoden und Operatoren auf so ein Klassen VTable umlenkt. Wenn du willst kannst du auch den compilierten Template Code kopieren und dann die Funktionsaufrufe wie oben gezeigt nachschlagen. Du erhälst zwar keinen Code der bis in den letzten Winkel micro optimiert ist allerdings ganz brauchbar ist und das viel schneller als wenn du den Code neuübersetzrn würdest.
Optimizer schrieb:
In C++ ist (Laufzeit)-Reflection deswegen schwierig zu realisieren, weil es hierfür einfach keine Compiler-Unterstützung und keinen Standard fürs dynamische Laden gibt.
Rate mal, wieso.
Hmm, vielleicht weil es viel Arbeit ist und wenig bringt? So in etwa wie mit export.
Meiner Meingung nach ist es Schwachsinn auf das statische Interface dynamisch zurück greifen zu wollen. Reflexion ist nützlich solang es dazu diehnt Klassen zu benutzen von denen man nur die Basisklasse kennt, hier nimmt es einem zum Beispiel ab das Factory Pattern implementiren zu müssen. Allerdings sobald man auf Funktionen zurückgreifen will deren Existenz du während der Übersetzung noch nicht mal ansatzweise geahnt hat, dann hast du ein dickes Denkproblem. Sollten solche Machenschaften bei Java die Regel sein (wovon ich nicht ausgehe), dann fange ich an zu verstehen wieso soviele Leute Java hassen.