Programmiersprache: Kotlin/Native stellt die Speicherverwaltung um
Die an Objective-C angelehnte Referenzzählung für das Memory-Management ist für Cross-Plattform und Multithreading ein Klotz am Bein.
JetBrains hat angekündigt, die Speicherverwaltung von Kotlin/Native maßgeblich umzustellen. Historisch lehnt sich das Projekt eng an die C-Obermenge Objective-C an, die für das Memory-Management auf Referenzzählung setzt. Der Ansatz ist jedoch für Multithreading-Anwendungen ebenso hinderlich wie für die übergreifende Entwicklung zwischen Kotlin auf der Java Virtual Machine (JVM) und Kotlin/Native.
Die Entwicklung von Kotlin/Native hatte JetBrains 2016 gestartet und 2017 vorgestellt. Erklärtes Ziel war, die Programmiersprache auf Plattformen ohne JVM zu bringen, allen voran Apples iOS. Verfügbar ist es zudem auf macOS, watchOS, tvOS sowie für Windows, Linux und Android, auch wenn es auf Googles mobilem Betriebssystem vor allem auf der JVM inzwischen Java den Rang abläuft. Daneben existiert das Kompilierziel WebAssembly für den nativen Ansatz der Programmiersprache.
Die Anfänge als Erbsenzähler
Da JetBrains mit Kotlin/Native besonders die Apple-Plattformen im Visier hatte, hat die Sprache einige Konzepte von Objective-C übernommen, darunter das Speichermanagement. Letzteres setzt die von Brad Cox in den 80-er Jahren entwickelte C-Obermenge über Referenzzählung um. Der Garbage Collector von Kotlin/Native setzt auf einen Trial-Deletion-Algorithmus. Wer in die Tiefen des automatisierten Aufräumens und der zugehörigen Algorithmen blicken möchte, findet eine Aufstellung der Methoden in einer wissenschaftlichen Abhandlung von IBM: "A Unified Theory of Garbage Collection".
Die Referenzzählung hat jedoch einige Nachteile, die mit der Zeit deutlicher wurden. Zum einen bremst sie Anwendungen, die häufig Speicher allozieren aus. Schwerer wiegen jedoch die Probleme, die für Multithreading-Anwendungen auftreten. Methoden, die Python und andere Programmiersprachen zum sicheren Umsetzen der Referenzzählung einsetzen wie der Global Interpreter Lock, seien für Kotlin/Native ungeeignet, da es für mobile Anwendungen unerlässlich sei, CPU-intensive Berechnungen in Hintergrund-Threads auszulagern, die parallel zum Main Thread laufen.
Eingefrorene Objekte
Kotlin/Native gibt daher eigene Beschränkungen vor, um Reference Counting und Multithreading möglichst effizient unter einen Hut zu bringen. Unter anderem müssen Threads den Objektgraph einfrieren, bevor sie ihn mit anderen Threads teilen, um Änderungen zu verhindern. Alternativ können sie eine losgelöste Version des Graphen weitergeben, auf den keine Referenzen im Original-Thread existieren.
Das Vorgehen soll recht effizient funktionieren, stößt aber spätestens für die übergreifende Entwicklung zwischen Kotlin auf der JVM und Kotlin/Native an seine Grenzen, wenn es an das Schreiben nebenläufigen Codes geht. Einige der Datenstrukturen und Synchronisations-Primitive, die auf der JVM funktionieren, lassen sich aufgrund der Beschränkungen nicht in Kotlin/Native verwirklichen.
Die Umsetzung der Koroutinen in kotlinx.coroutines
für Kotlin/Native, die seit Kotlin 1.3 als stabil gelten, führe zu Problemen und könne in Eckfällen zu Speicherlecks führen. Der bisherige Ansatz des Speichermanagements lässt wohl keine zufriedenstellende Anwendung zu.
Auf zu neuen Ufern
Daher hat das Kotlin/Native-Team die Arbeit an einem neuen Memory-Manager gestartet, der die Einschränkungen für das Teilen von Objekten beseitigen soll. Oberstes Ziel ist eine effiziente Nachverfolgung der Speichernutzung und Freigabe ungenutzter Bereiche sowie die vollständige Umsetzung von Programmiermethoden für die nebenläufige Programmierung, die ohne spezielle Annotationen auskommt.
Aus Gründen der Rückwärtskompatiblität sollen die derzeitig verwendeten Methoden wie das Einfrieren von Objekten weiterhin als Sicherheitsmaßnahme gegen Race Conditions beim Teilen von Daten in Multithreading-Anwendung erlaubt sein. Auch steht insgesamt das Verwenden von Immutable Data jenseits der nativen Variante auch im herkömmlichen Kotlin stärker an.
Allerdings steckt der neue Memory Manager wohl noch in den Kinderschuhen. Für die Zwischenzeit hat das Kotlin/Native-Team in dem Blogbeitrag zu den Plänen Multithreading Librarys für den derzeitigen Manager angekündigt.
(rme)