InteroperabilitätBearbeiten
Da Computersysteme häufig eine Interaktion zwischen neueren und älteren Anwendungen erfordern, bietet das .NET Framework Mittel, um auf Funktionen zuzugreifen, die in neueren und älteren Programmen implementiert sind, die außerhalb der .NET-Umgebung ausgeführt werden. Der Zugriff auf COM-Komponenten (Component Object Model) wird in den System.Runtime.InteropServices
– und System.EnterpriseServices
-Namensräumen des Frameworks bereitgestellt. Der Zugriff auf andere Funktionen erfolgt über Platform Invocation Services (P/Invoke). Der Zugriff auf .NET-Funktionen aus nativen Anwendungen erfolgt über die umgekehrte P/Invoke-Funktion.
Sprachunabhängigkeit
.NET Framework führt ein Common Type System (CTS) ein, das alle möglichen Datentypen und Programmierkonstrukte definiert, die von der CLR unterstützt werden, und wie sie entsprechend der CLI-Spezifikation interagieren können oder nicht. Aufgrund dieser Funktion unterstützt .NET Framework den Austausch von Typen und Objektinstanzen zwischen Bibliotheken und Anwendungen, die mit einer beliebigen konformen .NET-Sprache geschrieben wurden.
Typensicherheit
CTS und die in .NET Framework verwendete CLR erzwingen auch Typensicherheit. Dies verhindert schlecht definierte Casts, falsche Methodenaufrufe und Speichergrößenprobleme beim Zugriff auf ein Objekt. Dadurch sind auch die meisten CLI-Sprachen statisch typisiert (mit oder ohne Typinferenz). Ab .NET Framework 4.0 wurde die CLR jedoch durch die Dynamic Language Runtime erweitert, sodass dynamisch typisierte Sprachen auf der CLI implementiert werden können.
Portabilität
Während Microsoft das vollständige Framework nie auf einem anderen System als Microsoft Windows implementiert hat, hat es das Framework so entwickelt, dass es plattformübergreifend ist, und es sind Implementierungen für andere Betriebssysteme verfügbar (siehe Silverlight und § Alternative Implementierungen). Microsoft hat die Spezifikationen für CLI (einschließlich der Kern-Klassenbibliotheken, CTS und CIL), C# und C++/CLI sowohl bei der Ecma International (ECMA) als auch bei der International Organization for Standardization (ISO) eingereicht und sie damit als offizielle Standards verfügbar gemacht. Dies ermöglicht es Dritten, kompatible Implementierungen des Frameworks und seiner Sprachen auf anderen Plattformen zu erstellen.
SecurityEdit
.NET Framework hat einen eigenen Sicherheitsmechanismus mit zwei allgemeinen Funktionen: Code Access Security (CAS) sowie Validierung und Verifizierung. CAS basiert auf Beweisen, die mit einer bestimmten Assembly verbunden sind. Typischerweise ist der Beweis die Quelle der Assembly (ob sie auf dem lokalen Rechner installiert ist oder aus dem Internet heruntergeladen wurde). CAS verwendet Beweise, um die dem Code gewährten Berechtigungen zu bestimmen. Anderer Code kann verlangen, dass dem aufrufenden Code eine bestimmte Berechtigung gewährt wird. Die Anforderung führt dazu, dass die CLR einen Call Stack Walk durchführt: Jede Assembly jeder Methode im Call Stack wird auf die erforderliche Berechtigung überprüft; wenn einer Assembly die Berechtigung nicht gewährt wird, wird eine Sicherheitsausnahme ausgelöst.
Managed CIL Bytecode ist leichter zu reverse-engineeren als nativer Code, es sei denn, er ist obfuskiert. .NET-Decompiler-Programme ermöglichen es Entwicklern ohne Reverse-Engineering-Kenntnisse, den Quellcode hinter unverschleierten .NET-Assemblies einzusehen. Im Gegensatz dazu sind Anwendungen, die in nativen Maschinencode kompiliert wurden, viel schwieriger zurückzuentwickeln, und der Quellcode wird fast nie erfolgreich erstellt, hauptsächlich aufgrund von Compiler-Optimierungen und fehlender Reflexion. Dies führt zu Bedenken in der Geschäftswelt über den möglichen Verlust von Geschäftsgeheimnissen und die Umgehung von Lizenzkontrollmechanismen. Um dies abzumildern, hat Microsoft seit 2002 die Dotfuscator Community Edition in Visual Studio .NET integriert. Obfuskationstools von Drittanbietern sind ebenfalls erhältlich, z. B. von VMware, V.i. Labs, Turbo und Red Gate Software. Verschlüsselungstools auf Methodenebene für .NET-Code sind von Anbietern wie SafeNet erhältlich.
Speicherverwaltung
CLR befreit den Entwickler von der Last der Speicherverwaltung (Allokation und Freigabe, wenn diese erledigt ist); es übernimmt die Speicherverwaltung selbst, indem es erkennt, wann Speicher sicher freigegeben werden kann. Instanziierungen von .NET-Typen (Objekten) werden aus dem verwalteten Heap alloziert, einem Pool von Speicher, der von der CLR verwaltet wird. Solange ein Verweis auf ein Objekt vorhanden ist, der entweder direkt oder über einen Graphen von Objekten erfolgen kann, wird das Objekt als in Gebrauch betrachtet. Wenn kein Verweis auf ein Objekt existiert und es nicht erreicht oder verwendet werden kann, wird es zu Garbage, das heißt, es kann eingesammelt werden.
.NET Framework enthält einen Garbage Collector (GC), der periodisch in einem vom Thread der Anwendung getrennten Thread läuft, der alle unbrauchbaren Objekte aufzählt und den ihnen zugewiesenen Speicher zurückfordert. Es handelt sich um einen nicht-deterministischen, verdichtenden, mark-and-sweep Garbage Collector. GC wird nur ausgeführt, wenn eine bestimmte Menge an Speicher verbraucht wurde oder wenn das System einen gewissen Speicherdruck hat. Da nicht garantiert werden kann, wann die Bedingungen für die Rückgewinnung von Speicher erreicht sind, sind GC-Läufe nicht-deterministisch. Jede .NET-Anwendung hat einen Satz von Roots, die Zeiger auf Objekte auf dem verwalteten Heap (verwaltete Objekte) sind. Dazu gehören Verweise auf statische Objekte, Objekte, die als lokale Variablen oder Methodenparameter im aktuellen Gültigkeitsbereich definiert sind, und Objekte, auf die von CPU-Registern verwiesen wird. Wenn GC ausgeführt wird, hält es die Anwendung an und zählt dann für jedes Objekt, auf das im Stamm verwiesen wird, rekursiv alle von den Stammobjekten erreichbaren Objekte auf und markiert sie als erreichbar. Es verwendet CLI-Metadaten und Reflexion, um die von einem Objekt gekapselten Objekte zu ermitteln, und geht sie dann rekursiv durch. Anschließend werden alle Objekte auf dem Heap (die ursprünglich zusammenhängend alloziert wurden) mit Hilfe von Reflection aufgezählt. Alle nicht als erreichbar markierten Objekte sind Garbage. Dies ist die Markierungsphase. Da der von Garbage gehaltene Speicher keine Bedeutung hat, wird er als freier Speicher betrachtet. Allerdings verbleiben zwischen den Objekten, die ursprünglich zusammenhängend waren, Teile des Freiraums. Die Objekte werden dann zusammengedrückt, um den freien Speicherplatz auf dem verwalteten Heap wieder zusammenhängend zu machen. Jeder Verweis auf ein Objekt, der durch das Verschieben des Objekts ungültig wird, wird von GC aktualisiert, um die neue Position widerzuspiegeln. Nach Beendigung der Garbage Collection wird die Anwendung wieder fortgesetzt. Die neueste Version von .NET Framework verwendet die gleichzeitige Garbage Collection zusammen mit dem Anwendercode, wodurch Pausen nicht wahrnehmbar sind, da sie im Hintergrund abläuft.
Der von .NET Framework verwendete Garbage Collector ist ebenfalls generational. Objekten wird eine Generation zugewiesen. Neu erstellte Objekte werden mit Generation 0 gekennzeichnet. Objekte, die eine Garbage Collection überleben, werden mit Generation 1 gekennzeichnet. Objekte der Generation 1, die eine weitere Sammlung überleben, werden der Generation 2 zugeordnet. Das Framework verwendet Objekte bis zur Generation 2. Objekte der höheren Generation werden seltener als Objekte der niedrigeren Generation garbage collected. Dies erhöht die Effizienz der Garbage Collection, da ältere Objekte tendenziell eine längere Lebensdauer haben als neuere Objekte. Durch das Ignorieren älterer Objekte bei den meisten Sammlungsläufen sind insgesamt weniger Prüfungen und Verdichtungsoperationen erforderlich.
PerformanceEdit
Wenn eine Anwendung zum ersten Mal gestartet wird, kompiliert das .NET Framework den CIL-Code mithilfe seines Just-in-Time-Compilers in ausführbaren Code und speichert das ausführbare Programm im .NET Native Image Cache. Durch die Zwischenspeicherung wird die Anwendung bei nachfolgenden Starts schneller gestartet, obwohl der erste Start normalerweise langsamer ist. Um den ersten Start zu beschleunigen, können Entwickler das Dienstprogramm „Native Image Generator“ verwenden, um jede .NET-Anwendung manuell im Voraus zu kompilieren und zwischenzuspeichern.
Der in die Umgebung integrierte Garbage Collector kann unvorhergesehene Ausführungsverzögerungen einführen, über die der Entwickler wenig direkte Kontrolle hat. „In großen Anwendungen kann die Anzahl der Objekte, mit denen der Garbage Collector arbeiten muss, sehr groß werden, was bedeutet, dass es sehr lange dauern kann, alle diese Objekte zu besuchen und neu anzuordnen.“
.NET Framework bietet seit April 2014 in Visual Studio 2013 Update 2 Unterstützung für den Aufruf von Streaming SIMD Extensions (SSE) über verwalteten Code. Mono bietet jedoch bereits seit Version 2.2 im Mono.Simd-Namensraum Unterstützung für SIMD Extensions. Der leitende Entwickler von Mono, Miguel de Icaza, hat die Hoffnung geäußert, dass diese SIMD-Unterstützung vom ECMA-Standard der CLR übernommen wird. Streaming SIMD Extensions sind in x86-CPUs seit der Einführung des Pentium III verfügbar. Einige andere Architekturen wie ARM und MIPS haben ebenfalls SIMD-Erweiterungen. Für den Fall, dass die CPU diese Erweiterungen nicht unterstützt, werden die Anweisungen in Software simuliert.