{"id":39033,"date":"2023-12-06T19:29:21","date_gmt":"2023-12-06T18:29:21","guid":{"rendered":"https:\/\/www.happycoders.eu\/?p=39033"},"modified":"2025-06-12T08:35:30","modified_gmt":"2025-06-12T06:35:30","slug":"foreign-function-memory-api","status":"publish","type":"post","link":"https:\/\/www.happycoders.eu\/de\/java\/foreign-function-memory-api\/","title":{"rendered":"Java Foreign Function &#038; Memory API (FFM API)"},"content":{"rendered":"\n<p>Nach vielen Jahren der Entwicklung im Rahmen von <a href=\"https:\/\/openjdk.org\/projects\/panama\/\" target=\"_blank\" rel=\"noopener\">Project Panama<\/a> wurde die finale Version der \u201eForeign Function &amp; Memory API\u201d im M\u00e4rz 2024 mit <a href=\"\/de\/java\/java-22-features\/\">Java 22<\/a> ver\u00f6ffentlicht.<\/p>\n\n\n\n<p>In diesem Artikel erf\u00e4hrst du:<\/p>\n\n\n\n<ul class=\"wp-block-list hc-checked-list\">\n<li>Was ist die Foreign Function &amp; Memory API?<\/li>\n\n\n\n<li>Was ist der Unterschied zwischen FFM API und JNI?<\/li>\n\n\n\n<li>Wie ruft man mit der FFM API fremden Code auf?<\/li>\n\n\n\n<li>Wir schreibt und liest man mit der FFM API fremden Speicher?<\/li>\n\n\n\n<li><\/li>\n\n\n\n<li>Welche Bedeutung haben die Begriffe <em>Arena<\/em>, <em>Memory Segment<\/em>, <em>Memory Layout<\/em> und <em>Function Descriptor<\/em>?<\/li>\n<\/ul>\n\n\n\n<p>Den Quellcode zum Artikel findest du in diesem <a href=\"https:\/\/github.com\/SvenWoltmann\/ffm-api-demo\" target=\"_blank\" rel=\"noopener\">GitHub-Repository<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"was-ist-die-foreign-function-memory-api\">Was ist die Foreign Function &amp; Memory API?<\/h2>\n\n\n\n<p>Die Foreign Function &amp; Memory API (kurz: FFM API) erm\u00f6glicht es Java-Entwicklerinnen und <nobr>-Entwicklern<\/nobr>, Funktionen aus Libraries, die in anderen Programmiersprachen geschrieben wurden (<nobr>z. B.<\/nobr> die Standard-C-Library), unkompliziert aus Java heraus aufzurufen.<\/p>\n\n\n\n<p>Die FFM API erm\u00f6glicht es au\u00dferdem, aus Java heraus sicher auf Speicher zuzugreifen, der nicht von der JVM verwaltet wird, also Speicher au\u00dferhalb des Java-Heaps.<\/p>\n\n\n\n<p>Wie das funktioniert, zeige ich dir im \u00fcbern\u00e4chsten Abschnitt. Zun\u00e4chst solltest du wissen, warum die FFM API \u00fcberhaupt entwickelt wurde.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"unterschied-zwischen-der-ffm-api-und-jni\">Unterschied zwischen der FFM API und JNI<\/h2>\n\n\n\n<p>Um bisher auf nativen Code \u2013 also Code au\u00dferhalb der JVM \u2013 zuzugreifen, mussten Java-Entwickler das seit Java 1.1 existierende Java Native Interface (JNI) einsetzen. Wer das schon einmal gemacht hat, wei\u00df, dass das keine angenehme Aufgabe ist:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>JNI ist umst\u00e4ndlich zu benutzen: Man muss viel Java- und C-Boilerplate-Code schreiben und diesen mit \u00c4nderungen im nativen Code synchronisieren. Daf\u00fcr wurden zwar Tools bereitgestellt, doch die erleichtern die Aufgabe nur marginal.<\/li>\n\n\n\n<li>JNI ist fehleranf\u00e4llig: Fehler beim Zugriff auf nativen Speicher k\u00f6nnen die JVM leicht zum Absturz bringen.<\/li>\n\n\n\n<li>JNI ist extrem langsam.<\/li>\n<\/ul>\n\n\n\n<p>Die FFM API hingegen ist:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Einfach zu benutzen, wie du im folgenden Abschnitt sehen wirst. Der Implementierungsaufwand wurde mit der modernen FFM API gegen\u00fcber JNI laut Aussage der Panama-Entwickler um 90 % reduziert.<\/li>\n\n\n\n<li>Sicher: Zugriffe auf nativen Speicher werden durch sogenannte Arenen verwaltet, die sicherstellen, dass Speicheradressen g\u00fcltig sind und die andersfalls eine Exception werfen (anstatt die JVM abst\u00fcrzen zu lassen).<\/li>\n\n\n\n<li>Schnell: Die FFM API soll um Faktor vier bis f\u00fcnf schneller sein als JNI.<\/li>\n<\/ul>\n\n\n\n<p>Mit der Ver\u00f6ffentlichung der FFM API durch <a href=\"https:\/\/openjdk.org\/jeps\/454\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 454<\/a> gibt es nun keinen Grund mehr, JNI zu verwenden.<\/p>\n\n\n\n<p>Kommen wir nun zur spannenden Frage: Wie funktioniert die FFM API?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"foreign-function-memory-api-beispiele\">Foreign Function &amp; Memory API \u2013 Beispiele<\/h2>\n\n\n\n<p>Die neue API l\u00e4sst sich am besten anhand von Beispielen erkl\u00e4ren. Ich zeige dir zun\u00e4chst ein einfaches Beispiel, das die <code>strlen()<\/code>-Funktion der Standard-C-Library aufruft. Danach folgt ein komplexeres Beispiel, das die C-<code>qsort()<\/code>-Funktion aufruft, welche wiederum eine Java-Callback-Funktion zum Vergleich zweier Elemente aufruft.<\/p>\n\n\n\n<p>Im Anschluss werde ich dir die eingesetzten Komponenten der Foreign Function &amp; Memory API detaillierter erkl\u00e4ren. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"beispiel-1-strlen-funktion-der-standard-c-library\">Beispiel 1: strlen()-Funktion der Standard-C-Library<\/h3>\n\n\n\n<p>Beginnen wir mit einem sehr einfachen Beispiel (du findest es in der Klasse <a href=\"https:\/\/github.com\/SvenWoltmann\/ffm-api-demo\/blob\/main\/src\/main\/java\/eu\/happycoders\/ffm\/FFMTestStrlen.java\" target=\"_blank\" rel=\"noopener\">FFMTestStrlen<\/a> im GitHub-Repository). Der folgende Code verwendet die <code>strlen()<\/code>-Methode der Standard-C-Library, um die L\u00e4nge des Strings \u201eHappy Coding!\u201d zu berechnen. <\/p>\n\n\n\n<p>Schauen wir uns einmal die Definition dieser C-Funktion an:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"C++\" data-shcb-language-slug=\"cpp\"><span><code class=\"hljs language-cpp\"><span class=\"hljs-function\"><span class=\"hljs-built_in\">std<\/span>::<span class=\"hljs-keyword\">size_t<\/span> <span class=\"hljs-title\">strlen<\/span><span class=\"hljs-params\">( <span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">char<\/span>* str )<\/span><\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">C++<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cpp<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Die Methode hat einen Parameter:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>str<\/code> \u2013 Zeiger auf den zu untersuchenden, Null-terminierten String<\/li>\n<\/ul>\n\n\n\n<p>Der R\u00fcckgabetyp, <code>size_t<\/code>, steht f\u00fcr einen unsignierten Integer.<\/p>\n\n\n\n<p>Ich zeige dir erstmal das Programm zum Aufruf dieser Methode. Eine kurze Erl\u00e4uterung der einzelnen Schritte findest du in den Kommentaren, eine ausf\u00fchrlichere Erkl\u00e4rung unterhalb des Programmcodes.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">FFMTestStrlen<\/span> <\/span>{\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">(String&#091;] args)<\/span> <span class=\"hljs-keyword\">throws<\/span> Throwable <\/span>{\n    <span class=\"hljs-comment\">\/\/ 1. Get a linker \u2013 the central element for accessing foreign functions<\/span>\n    Linker linker = Linker.nativeLinker();\n\n    <span class=\"hljs-comment\">\/\/ 2. Get a lookup object for commonly used libraries<\/span>\n    SymbolLookup stdlib = linker.defaultLookup();\n\n    <span class=\"hljs-comment\">\/\/ 3. Get the address of the \"strlen\" function in the C standard library<\/span>\n    MemorySegment strlenAddress = stdlib.find(<span class=\"hljs-string\">\"strlen\"<\/span>).orElseThrow();\n\n    <span class=\"hljs-comment\">\/\/ 4. Define the input and output parameters of the \"strlen\" function<\/span>\n    FunctionDescriptor descriptor =\n        FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS);\n\n    <span class=\"hljs-comment\">\/\/ 5. Get a handle to the \"strlen\" function<\/span>\n    MethodHandle strlen = linker.downcallHandle(strlenAddress, descriptor);\n\n    <span class=\"hljs-comment\">\/\/ 6. Get a confined memory area (one that we can close explicitly)<\/span>\n    <span class=\"hljs-keyword\">try<\/span> (Arena offHeap = Arena.ofConfined()) {\n\n      <span class=\"hljs-comment\">\/\/ 7. Convert the Java String to a C string and store it in off-heap memory<\/span>\n      MemorySegment str = offHeap.allocateFrom(<span class=\"hljs-string\">\"Happy Coding!\"<\/span>);\n\n      <span class=\"hljs-comment\">\/\/ 8. Invoke the \"strlen\" function<\/span>\n      <span class=\"hljs-keyword\">long<\/span> len = (<span class=\"hljs-keyword\">long<\/span>) strlen.invoke(str);\n      System.out.println(<span class=\"hljs-string\">\"len = \"<\/span> + len);\n    }\n    <span class=\"hljs-comment\">\/\/ 9. Off-heap memory is deallocated at end of try-with-resources<\/span>\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Was genau passiert in diesem Code? (Die folgende Nummerierung verweist auf die entsprechenden Kommentare im Quellcode.)<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u00dcber die statische Methode <code>Linker.nativeLinker()<\/code> bekommen wir einen Linker \u2013 die zentrale Komponente, die den Zugriff auf fremde Funktionen orchestriert.<\/li>\n\n\n\n<li>\u00dcber <code>Linker.defaultLookup()<\/code> lassen wir uns ein <code>SymbolLookup<\/code>-Objekt liefern, \u00fcber das wir die Speicheradressen von Methoden h\u00e4ufig verwendeter Bibliotheken abrufen k\u00f6nnen. Welche Bibliotheken das sind, h\u00e4ngt von Betriebssystem und CPU ab.<\/li>\n\n\n\n<li>Mit <code>SymbolLookup.find(...)<\/code> fragen wir nach der Speicheradresse der \u201estrlib\u201d-Funktion. Die Methode liefert ein <code>Optional&lt;MemorySegment&gt;<\/code> zur\u00fcck, welches leer ist, sollte die Methode nicht existieren.<\/li>\n\n\n\n<li>Mit einem sogenannten <em>Function Descriptor<\/em> geben wir an, welche Ein- und Ausgabeparameter die <code>strlib()<\/code>-Methode hat. Das erste Argument, <code>ValueLayout.JAVA_LONG<\/code>, definiert den R\u00fcckgabetyp der Methode. Das zweite Argument, <code>ValueLayout.ADDRESS<\/code>, definiert den Typ des ersten (und einzigen) Methodenparameters als Speicheradresse (die des Strings, dessen L\u00e4nge wir bestimmen wollen). Der Funktionsdeskriptor wird beim Aufruf der nativen Funktion sicherstellen, dass Java-Typen ordnungsgem\u00e4\u00df in C-Typen umgewandelt werden und umgekehrt.<\/li>\n\n\n\n<li>Die Methode <code>Linker.downcallHandle(...)<\/code> liefert uns ein <code>MethodHandle<\/code> f\u00fcr die Methode an der angegebenen Speicheradresse und den zuvor definierten Funktionsdeskriptor. Method Handles sind nichts Neues \u2013 es gibt sie bereits seit Java 7.<\/li>\n\n\n\n<li><code>Arena.ofConfined()<\/code> liefert uns eine sogenannte <em>Arena<\/em> \u2013 ein Objekt, das den Zugriff auf nativen Speicher verwaltet \u2013 mehr dazu sp\u00e4ter.<\/li>\n\n\n\n<li><code>Arena.allocateFrom(...)<\/code> reserviert einen nativen Speicherblock und legt dort die Zeichenkette \u201eHappy Coding!\u201d im UTF-8-Format ab.<\/li>\n\n\n\n<li>Mit <code>MethodHandle.invoke(...)<\/code> rufen wir die C-<code>strlen()<\/code>-Methode auf; das Ergebnis casten wir zu einem <code>long<\/code> (der in Schritt 3 definierte <em>Function Descriptor<\/em> stellt sicher, dass wir das tun k\u00f6nnen).<\/li>\n\n\n\n<li>Am Ende des <em>try-with-resources<\/em>-Block wird <code>Arena.close()<\/code> aufgerufen und damit alle Speicherbl\u00f6cke, die \u00fcber diese Arena verwaltet werden, freigegeben.<\/li>\n<\/ol>\n\n\n\n<p>Die hier gezeigten Elemente der Foreign Function &amp; Memory API \u2013 <em>Memory Segment<\/em>, <em>Arena<\/em>, <em>Value Layout<\/em> und <em>Function Descriptor<\/em> \u2013 werden im Kapitel <a href=\"#komponenten-der-ffm-api\">Komponenten der FFM API<\/a> noch einmal n\u00e4her beschrieben.  <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Start des Beispiel-Programms<\/h4>\n\n\n\n<p>Wenn du den Quellcode in der Datei <em>FFMTestStrlen.java<\/em> speicherst, kannst du ihn wie folgt ausf\u00fchren:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ java FFMTestStrlen.java \nWARNING: A restricted method in java.lang.foreign.Linker has been called\nWARNING: java.lang.foreign.Linker::downcallHandle has been called by eu.happycoders.java22.ffm.FFMTestStrlen in an unnamed module\nWARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module\nWARNING: Restricted methods will be blocked in a future release unless native access is enabled\n\nlen = 13<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Um die Warnung zu unterdr\u00fccken, musst du das Programm wie folgt starten:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ java --enable-native-access=ALL-UNNAMED FFMTestStrlen.java\nlen = 13<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Die String-L\u00e4nge wurde korrekt berechnet!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"beispiel-2-qsort-funktion-der-standard-c-library\">Beispiel 2: qsort()-Funktion der Standard-C-Library<\/h3>\n\n\n\n<p>Als n\u00e4chstes wollen wir uns an ein komplexeres Beispiel wagen. Wir wollen mit der <code>qsort()<\/code>-Funktion ein Array von Integers sortieren. Wir m\u00fcssen dazu erstmal einen Blick auf die Definiton dieser Funktion werfen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"C++\" data-shcb-language-slug=\"cpp\"><span><code class=\"hljs language-cpp\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">qsort<\/span><span class=\"hljs-params\">( <span class=\"hljs-keyword\">void<\/span> *ptr, <span class=\"hljs-keyword\">size_t<\/span> count, <span class=\"hljs-keyword\">size_t<\/span> size,\n            <span class=\"hljs-keyword\">int<\/span> (*comp)(<span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">void<\/span> *, <span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">void<\/span> *) )<\/span><\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">C++<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cpp<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Die Methode verwendet die folgenden Parameter:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>ptr<\/code> \u2013 Zeiger auf das zu sortierende Array<\/li>\n\n\n\n<li><code>count<\/code> \u2013 Anzahl der Elemente im Array<\/li>\n\n\n\n<li><code>size<\/code> \u2013 Gr\u00f6\u00dfe der einzelnen Elemente des Arrays in Bytes<\/li>\n\n\n\n<li><code>comp<\/code> \u2013 Vergleichsfunktion, die einen negativen ganzzahligen Wert zur\u00fcckgibt, wenn das erste Argument kleiner als das zweite ist, einen positiven ganzzahligen Wert, wenn das erste Argument gr\u00f6\u00dfer als das zweite ist, und Null, wenn die Argumente gleich sind.<\/li>\n<\/ul>\n\n\n\n<p>Signatur der Vergleichsfunktion:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"C++\" data-shcb-language-slug=\"cpp\"><span><code class=\"hljs language-cpp\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">cmp<\/span><span class=\"hljs-params\">(<span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">void<\/span> *a, <span class=\"hljs-keyword\">const<\/span> <span class=\"hljs-keyword\">void<\/span> *b)<\/span><\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">C++<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cpp<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Ich zeige dir wieder zun\u00e4chst den vollst\u00e4ndigen Programmcode mit Kommentaren. Im Anschluss erkl\u00e4re ich dir die neuen Komponenten dieses Beispiels ausf\u00fchrlicher.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">FFMTestQsort<\/span> <\/span>{\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">(String&#091;] args)<\/span> <span class=\"hljs-keyword\">throws<\/span> Throwable <\/span>{\n    <span class=\"hljs-comment\">\/\/ 1. Get a linker - the central element for accessing foreign functions<\/span>\n    Linker linker = Linker.nativeLinker();\n\n    <span class=\"hljs-comment\">\/\/ 2. Get a lookup object for commonly used libraries<\/span>\n    SymbolLookup stdlib = linker.defaultLookup();\n\n    <span class=\"hljs-comment\">\/\/ 3. Get the address of the \"qsort\" function in the C standard library<\/span>\n    MemorySegment qsortAddress = stdlib.find(<span class=\"hljs-string\">\"qsort\"<\/span>).orElseThrow();\n\n    <span class=\"hljs-comment\">\/\/ 4. Define the input and output parameters of the \"qsort\" function:<\/span>\n    FunctionDescriptor qsortDescriptor =\n        FunctionDescriptor.ofVoid(\n            ValueLayout.ADDRESS, \n            ValueLayout.JAVA_LONG,\n            ValueLayout.JAVA_LONG,\n            ValueLayout.ADDRESS);\n\n    <span class=\"hljs-comment\">\/\/ 5. Get a method handle to the \"qsort\" function<\/span>\n    MethodHandle qsortHandle = linker.downcallHandle(qsortAddress, qsortDescriptor);\n\n    <span class=\"hljs-comment\">\/\/ 6. Define the input and output parameters of the \"compare\" function:<\/span>\n    FunctionDescriptor compareDescriptor =\n        FunctionDescriptor.of(\n            ValueLayout.JAVA_INT,\n            ValueLayout.ADDRESS.withTargetLayout(ValueLayout.JAVA_INT),\n            ValueLayout.ADDRESS.withTargetLayout(ValueLayout.JAVA_INT));\n\n    <span class=\"hljs-comment\">\/\/ 7. Get a handle to the \"compare\" function<\/span>\n    MethodHandle compareHandle =\n        MethodHandles.lookup()\n            .findStatic(FFMTestQsort<span class=\"hljs-class\">.<span class=\"hljs-keyword\">class<\/span>, \"<span class=\"hljs-title\">compare<\/span>\", <span class=\"hljs-title\">compareDescriptor<\/span>.<span class=\"hljs-title\">toMethodType<\/span>())<\/span>;\n\n    <span class=\"hljs-comment\">\/\/ 8. Get a confined memory area (one that we can close explicitly)<\/span>\n    <span class=\"hljs-keyword\">try<\/span> (Arena offHeap = Arena.ofConfined()) {\n      <span class=\"hljs-comment\">\/\/ 9. Allocate off-heap memory and store unsorted array in it<\/span>\n      <span class=\"hljs-keyword\">int<\/span>&#091;] unsorted = createUnsortedArray();\n      MemorySegment arrayAddress = offHeap.allocateFrom(ValueLayout.JAVA_INT, unsorted);\n\n      <span class=\"hljs-comment\">\/\/ 10. Allocate off-head memory for an \"upcall stub\" to the comparison function<\/span>\n      MemorySegment compareAddress =\n          linker.upcallStub(compareHandle, compareDescriptor, offHeap);\n\n      <span class=\"hljs-comment\">\/\/ 11. Invoke the qsort function<\/span>\n      qsortHandle.invoke(\n          arrayAddress, \n          unsorted.length, \n          ValueLayout.JAVA_INT.byteSize(), \n          compareAddress);\n\n      <span class=\"hljs-comment\">\/\/ 12. Read array from off-heap memory<\/span>\n      <span class=\"hljs-keyword\">int<\/span>&#091;] sorted = arrayAddress.toArray(ValueLayout.JAVA_INT);\n      System.out.println(<span class=\"hljs-string\">\"sorted   = \"<\/span> + Arrays.toString(sorted));\n    }\n    <span class=\"hljs-comment\">\/\/ 13. Off-heap memory is deallocated at end of try-with-resources<\/span>\n  }\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">int<\/span> <span class=\"hljs-title\">compare<\/span><span class=\"hljs-params\">(MemorySegment aAddr, MemorySegment bAddr)<\/span> <\/span>{\n    <span class=\"hljs-keyword\">int<\/span> a = aAddr.get(ValueLayout.JAVA_INT, <span class=\"hljs-number\">0<\/span>);\n    <span class=\"hljs-keyword\">int<\/span> b = bAddr.get(ValueLayout.JAVA_INT, <span class=\"hljs-number\">0<\/span>);\n    <span class=\"hljs-keyword\">return<\/span> Integer.compare(a, b);\n  }\n\n  <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">int<\/span>&#091;] createUnsortedArray() {\n    ThreadLocalRandom random = ThreadLocalRandom.current();\n    <span class=\"hljs-keyword\">int<\/span>&#091;] unsorted = IntStream.generate(() -&gt; random.nextInt(<span class=\"hljs-number\">1000<\/span>)).limit(<span class=\"hljs-number\">10<\/span>).toArray();\n    System.out.println(<span class=\"hljs-string\">\"unsorted = \"<\/span> + Arrays.toString(unsorted));\n    <span class=\"hljs-keyword\">return<\/span> unsorted;\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Die Besonderheiten dieses Programms im Vergleich zum vorherigen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Schritt 4: F\u00fcr den Funktionsdescriptor verwenden wir die Methode <code>FunctionDescriptor.ofVoid(...)<\/code>, da <code>qsort(...)<\/code> keinen R\u00fcckgabewert hat. Wir geben die folgenden Argumente an:\n<ul class=\"wp-block-list\">\n<li><code>ValueLayout.ADDRESS<\/code> \u2013 f\u00fcr den Zeiger auf das zu sortierende Array<\/li>\n\n\n\n<li><code>ValueLayout.JAVA_LONG<\/code> \u2013 f\u00fcr die Anzahl der Elemente im Array<\/li>\n\n\n\n<li><code>ValueLayout.JAVA_LONG<\/code> \u2013 f\u00fcr die Gr\u00f6\u00dfe der einzelnen Array-Elemente<\/li>\n\n\n\n<li><code>ValueLayout.ADDRESS<\/code> \u2013 f\u00fcr die Adresse der Vergleichsfunktion<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Schritt 6: Hier definieren wir einen Funktionsdeskriptor f\u00fcr die Vergleichsfunktion: das erste Argument, <code>ValueLayout.JAVA_INT<\/code>, gibt den R\u00fcckgabetyp an; das zweite und dritte Argument, jeweils <code>ValueLayout.ADDRESS.withTargetLayout(ValueLayout.JAVA_INT)<\/code> stehen f\u00fcr die Speicheradressen jeweils zweier zu vergleichender Array-Elemente.<\/li>\n\n\n\n<li>Schritt 7: Hier lassen wir uns ein Method Handle f\u00fcr die Vergleichsfunktion generieren.<\/li>\n\n\n\n<li>Schritt 9: Mit der Methode <code>Arena.allocateFrom(...)<\/code> allokieren wir Off-Heap-Speicher f\u00fcr ein Integer-Array und speichern darin das \u00fcbergebene Array.<\/li>\n\n\n\n<li>Schritt 10: Mit <code>Linker.upcallStub(...)<\/code> allokieren wir Off-Heap-Speicher f\u00fcr einen sogenannten \u201eUpcall Stub\u201d f\u00fcr die Vergleichsfunktion. \u00dcber diesen Stub kann sp\u00e4ter die C-Funktion die Java-Callback-Methode <code>compare(...)<\/code> aufrufen.<\/li>\n\n\n\n<li>Schritt 11: Die Adresse dieses Stubs geben wir als viertes Argument beim Aufruf der <code>qsort(...)<\/code>-Methode an.<\/li>\n\n\n\n<li>Schritt 12: Mit <code>MemorySegment.toArray(...)<\/code> wandeln wir das an der Off-Heap-Speicheradresse <code>arrayAddress<\/code> gespeicherte Array zur\u00fcck in ein Java-Array.<\/li>\n<\/ul>\n\n\n\n<p>Du findest den vollst\u00e4ndigen Programmcode in der Klasse <a href=\"https:\/\/github.com\/SvenWoltmann\/ffm-api-demo\/blob\/main\/src\/main\/java\/eu\/happycoders\/ffm\/FFMTestQsort.java\" target=\"_blank\" rel=\"noopener\">FFMTestQsort<\/a> im GitHub-Repository.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Start des Beispiel-Programms<\/h4>\n\n\n\n<p>Wir starten das Programm wie folgt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">$ java --enable-native-access=ALL-UNNAMED FFMTestQsort.java\nunsorted = &#091;696, 788, 659, 413, 933, 143, 93, 200, 736, 300]\nsorted   = &#091;93, 143, 200, 300, 413, 659, 696, 736, 788, 933]<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Unser Programm hat erfolgreich zehn Zahlen mit <code>qsort()<\/code> sortiert.<\/p>\n\n\n<div class=\"convertkit-form wp-block-convertkit-form\" style=\"\"><script async data-uid=\"1427197203\" src=\"https:\/\/happycoders.kit.com\/1427197203\/index.js\" data-jetpack-boost=\"ignore\" data-no-defer=\"1\" data-no-optimize=\"1\" nowprocket><\/script><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"komponenten-der-ffm-api\">Komponenten der FFM API<\/h2>\n\n\n\n<p>Anhand der Beispiele hast du die wichtigsten Komponenten der Foreign Function &amp; Memory API \u2013 <em>Arena<\/em>, <em>Memory Segment<\/em>, <em>Function Descriptor<\/em> und <em>Value Layout<\/em> \u2013 kennengelernt. In diesem Kapitel gehe ich detaillierter auf diese Komponenten ein.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"arena\">Arena<\/h3>\n\n\n\n<p>Eine Arena verwaltet den Zugriff auf nativen Speicher und stellt sicher, dass allokierte Speicherbl\u00f6cke wieder freigegeben werden und dass wir nicht auf bereits freigegebenen Speicher zugreifen.<\/p>\n\n\n\n<p>Es gibt vier Typen von Arenen, die wir \u00fcber statische Factory-Methoden der <code>Arena<\/code>-Klasse erzeugen k\u00f6nnen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>die globale (\u201eglobal\u201d) Arena,<\/li>\n\n\n\n<li>vom Garbage Collector automatisch verwaltete (\u201eauto\u201d) Arenen, <\/li>\n\n\n\n<li>beschr\u00e4nkte (\u201econfined\u201d) Arenen und<\/li>\n\n\n\n<li>geteilte (\u201eshared\u201d) Arenen.<\/li>\n<\/ul>\n\n\n\n<p>In den folgenden Abschnitten lernst du die Unterschiede der verschiedenen Typen kennen.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Globale Arena<\/h4>\n\n\n\n<p>Von der globalen Arena existiert nur eine einzige Instanz, die von allen Anwendungsthreads geteilt wird. In der globalen Arena allokierte Speichersegmente werden erst beim Beenden der JVM wieder freigegeben.<\/p>\n\n\n\n<p>Die globale Arena erh\u00e4lst du wie folgt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Arena arena = Arena.global();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Du kannst die globale Arena nicht schlie\u00dfen. Ein Aufruf von <code>Arena.global().close()<\/code> resultiert in einer <code>UnsupportedOperationException<\/code>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Automatische Arena<\/h4>\n\n\n\n<p>In einer automatischen Arena allokierte Speichersegmente werden vom Garbage Collector freigegeben, sobald keine Refenzen auf die entsprechenden <code>MemorySegment<\/code>-Objekte mehr existieren.<\/p>\n\n\n\n<p>Eine automatische Arena kann ebenfalls von allen Anwendungsthreads verwendet werden. Du erzeugst sie wie folgt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Arena arena = Arena.ofAuto();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Beachte, dass jeder Aufruf von <code>Arena.ofAuto()<\/code> eine neue automatische Arena erzeugt.<\/p>\n\n\n\n<p>Eine automatische Arena wird dann geschlossen, wenn keine Referenzen mehr auf die Arena selbst und auf alle \u00fcber sie allokierten Speichersegmente existieren. Ein manueller Aufruf von <code>Arena.global().close()<\/code> f\u00fchrt zu einer <code>UnsupportedOperationException<\/code>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Beschr\u00e4nkte (\u201econfined\u201d) Arena<\/h4>\n\n\n\n<p>Eine automatische Arena hat den Nachteil, dass das Deallokieren der Speichersegmente nicht deterministisch ist. Es passiert erst dann, wenn der Garbage Collector l\u00e4uft und feststellt, dass es keine Referenzen mehr auf diese gibt.<\/p>\n\n\n\n<p>Es gibt Anwendungsf\u00e4lle, in denen wir selbst entscheiden wollen, wann der \u00fcber eine Arena allokierte Speicher freigegeben wird. Daf\u00fcr gibt es die sogenannten beschr\u00e4nkten (\u201econfined\u201d) Arenen, wie wir sie auch in der Beispiel-Anwendung verwendet haben.<\/p>\n\n\n\n<p>Die von einer beschr\u00e4nkten Arena allokierten Speichersegmente werden dann freigegeben, wenn die Arena durch den Aufruf von <code>close()<\/code> geschlossen wird. Da die <code>Arena<\/code>-Klasse auto-closeable ist, sollten wir die Arena in einem <em>try-with-resources<\/em> Block erzeugen: <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">try<\/span> (Arena arena = Arena.ofConfined()) {\n  . . .\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Alle innerhalb dieses Blocks allokierten Speichersegmente werden am Ende des Blocks durch den impliziten Aufruf von <code>arena.close()<\/code> freigegeben.<\/p>\n\n\n\n<p>Der Versuch eine bereits geschlossene Arena zu verwenden, f\u00fchrt zu einer <code>IllegalStateException<\/code>.<\/p>\n\n\n\n<p>Beschr\u00e4nkte Arenen d\u00fcrfen nur in dem Threads verwendet werden, in dem sie erzeugt wurden.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Geteilte (\u201eshared\u201d) Arena<\/h4>\n\n\n\n<p>Eine geteilte Arena kombiniert die Vorteile der beschr\u00e4nkten Arena (deterministische Lebenszeit der Speichersegmente) mit der M\u00f6glichkeit, aus mehreren Threads verwendet zu werden. Du erzeugst eine geteilte Arena wie folgt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">Arena arena = Arena.ofShared()<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Eine geteilte Arena wird geschlossen, sobald ein beliebiger Thread deren <code>close()<\/code>-Methode aufruft. Sollte danach ein anderer Thread versuchen, die Arena zu verwenden, kommt es zu einer <code>IllegalStateException<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"memorysegment\">MemorySegment<\/h3>\n\n\n\n<p>Ein <code>MemorySegment<\/code> ist ein Objekt, dass einen zusammenh\u00e4ngenden Speicherbereich beschreibt. Ein Memory Segment kann auf verschiedene Arten allokiert werden. Die <code>Arena<\/code>-Klasse bietet dazu u. a. folgende Methoden an: <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>Arena.allocateFrom(String str)<\/code> <br>allokiert ein Memory Segment und speichert darin den \u00fcbergebenen String als UTF-8-kodierte Bytefolge. Diese Methode haben wir im Beispiel oben verwendet. <\/li>\n\n\n\n<li><code>allocate(long byteSize)<\/code> <br>allokiert ein Speichersegment der angegebenen Gr\u00f6\u00dfe.<\/li>\n\n\n\n<li><code>allocate(MemoryLayout elementLayout)<\/code><br><code>allocate(MemoryLayout elementLayout, long count)<\/code><br>allokieren ein Speichersegment, dessen Gr\u00f6\u00dfe genau auf eine bestimmte Anzahl (1 in der ersten Variante, <code>count<\/code> in der zweiten Variante) von Objekten eines bestimmten Typs (definiert durch <code>elementLayout<\/code>) abgestimmt ist. Die <code>MemoryLayout<\/code>-Klasse beschreibe ich im n\u00e4chsten Abschnitt.<\/li>\n<\/ul>\n\n\n\n<p>Eine vollst\u00e4ndige \u00dcbersicht aller Methoden zum Allokieren von Speichersegmenten findest du in der <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/22\/docs\/api\/java.base\/java\/lang\/foreign\/Arena.html\" target=\"_blank\" rel=\"noopener\">JavaDoc-Dokumentation von Arena<\/a> und <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/22\/docs\/api\/java.base\/java\/lang\/foreign\/SegmentAllocator.html\" target=\"_blank\" rel=\"noopener\">SegmentAllocator<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"memorylayout\">MemoryLayout<\/h3>\n\n\n\n<p>Ein <code>MemoryLayout<\/code> definiert den Speicheraufbau eines bestimmten Typs, wobei dieser Typ auch eine Kombination anderer Typen sein kann (z. B. ein Array oder Struct).<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">ValueLayout<\/h4>\n\n\n\n<p><code>ValueLayout<\/code> ist eine Unterklasse von <code>MemoryLayout<\/code>, die definiert, wie grundlegende Datentypen wie z. B. <code>int<\/code>, <code>long<\/code> und <code>double<\/code> im Speicher repr\u00e4sentiert werden.<\/p>\n\n\n\n<p>Im Beispiel haben wir mit <code>ValueLayout.JAVA_LONG<\/code> den primitiven Java-Typ <code>long<\/code> beschrieben und mit <code>ValueLayout.ADDRESS<\/code> eine Speicheradresse der zugrunde liegenden Hardware.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">SequenceLayout<\/h4>\n\n\n\n<p>Ein <code>SequenceLayout<\/code>, ebenfalls eine Unterklasse von <code>MemoryLayout<\/code>, beschreibt ein Array eines bestimmten Typs, wobei dieser Typ wiederum durch ein <code>MemoryLayout<\/code> beschrieben wird. Der folgende Code definiert z. B. ein Array mit zehn Java-Doubles:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">MemoryLayout.sequenceLayout(<span class=\"hljs-number\">10<\/span>, ValueLayout.JAVA_DOUBLE);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Und der folgende Code definiert das Speicherlayout f\u00fcr ein Array bestehend aus drei Arrays zu je zehn Integer-Arrays:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">MemoryLayout.sequenceLayout(3, \n    MemoryLayout.sequenceLayout(10, ValueLayout.JAVA_INT));<\/code><\/span><\/pre>\n\n\n<h4 class=\"wp-block-heading\">StructLayout<\/h4>\n\n\n\n<p>Ein <code>StructLayout<\/code>, auch eine Unterklasse von <code>MemoryLayout<\/code>, beschreibt das Speicherlayout eines Structs, also eines Speicherbereichs, in dem verschiedene Datentypen hintereinander abgelegt abgelegt sind. Die Elemente des Structs haben einen Namen und wiederum ein <code>MemoryLayout<\/code>. Der Name wird nicht mit gespeichert, sondern wird daf\u00fcr verwendet, um auf die Elemente des Structs zuzugreifen.<\/p>\n\n\n\n<p>Der folgende Code beschreibt das Speicherlayout f\u00fcr ein Struct, das ein Jahr, einen Monat und einen Tag enth\u00e4lt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\">MemoryLayout.structLayout(\n    ValueLayout.JAVA_SHORT.withName(<span class=\"hljs-string\">\"year\"<\/span>),\n    ValueLayout.JAVA_SHORT.withName(<span class=\"hljs-string\">\"month\"<\/span>), \n    ValueLayout.JAVA_SHORT.withName(<span class=\"hljs-string\">\"day\"<\/span>));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Ein Struct kann auch Arrays oder wiederum Structs enthalten.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"functiondescriptor\">FunctionDescriptor<\/h3>\n\n\n\n<p>Mit einem <code>FunctionDescriptor<\/code> beschreiben wir die Ein- und Ausgabeparameter einer nativen Funktion. Beim Aufruf einer nativen Funktion \u00fcber ein Method Handle sorgt der Funktionsdeskriptor daf\u00fcr, dass die \u00fcbergebenen Java-Typen in die korrekten C-Typen umgewandelt werden und der R\u00fcckgabewert von einem C-Typen in den gew\u00fcnschten Java-R\u00fcckgabewert.<\/p>\n\n\n\n<p>Die Klasse <code>FunctionDescriptor<\/code> hat zwei statische Methoden:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>of(MemoryLayout resLayout, MemoryLayout... argLayouts)<br><\/code>erzeugt einen Function Descriptor mit dem durch <code>resLayout<\/code> definierten R\u00fcckgabetyp und den durch <code>argLayouts<\/code> definierten Eingabetypen.<\/li>\n\n\n\n<li><code>ofVoid(MemoryLayout... argLayouts)<br><\/code>erzeugt einen Function Descriptor ohne R\u00fcckgabetyp und mit den durch <code>argLayouts<\/code> definierten Eingabetypen.<\/li>\n<\/ul>\n\n\n\n<p>Du hast nun die Grundelemente der Foreign Function &amp; Memory API kennengelernt. Wie diese Elemente zusammenarbeiten, um Speicherbereiche zu schreiben und zu lesen, erf\u00e4hrst du im folgenden Kapitel.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"schreiben-und-lesen-von-memory-segmenten\">Schreiben und Lesen von Memory-Segmenten<\/h2>\n\n\n\n<p>In diesem Kapitel lernst du, wie du auf den durch ein <code>MemorySegment<\/code> verwalteten Speicherbereich schreibend und lesend zugreifen kannst.<\/p>\n\n\n\n<p>Wir beginnen mit einem einfachen Beispiel mit einem <code>ValueLayout<\/code>, gehen zu einem komplizierten Beispiel mit einem <code>SequenceLayout<\/code> und kommen schlie\u00dflich zu einem sehr komplexen Beispiel mit einer Kombination aus <code>SequenceLayout<\/code> und <code>StructLayout<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"memorysegment-und-valuelayout\">MemorySegment und ValueLayout<\/h3>\n\n\n\n<p>Das folgende Programm (Klasse <a href=\"https:\/\/github.com\/SvenWoltmann\/ffm-api-demo\/blob\/main\/src\/main\/java\/eu\/happycoders\/ffm\/FFMTestInts.java\" target=\"_blank\" rel=\"noopener\">FFMTestInts<\/a> im GitHub-Repo) legt in der globalen Arena ein <code>MemorySegment<\/code> mit 100 Java-Integern an, f\u00fcllt dieses unter Verwendung von <code>MemorySegment.setAtIndex(...)<\/code> mit Zufallszahlen und liest danach alle 100 Zahlen mit <code>MemorySegment.getAtIndex(...)<\/code> wieder aus:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">FFMTestInts<\/span> <\/span>{\n  <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-keyword\">int<\/span> COUNT = <span class=\"hljs-number\">100<\/span>;\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">(String&#091;] args)<\/span> <\/span>{\n    MemorySegment numbers = Arena.global().allocate(ValueLayout.JAVA_INT, COUNT);\n\n    ThreadLocalRandom random = ThreadLocalRandom.current();\n    <span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-keyword\">int<\/span> i = <span class=\"hljs-number\">0<\/span>; i &lt; COUNT; i++) {\n      numbers.setAtIndex(ValueLayout.JAVA_INT, i, random.nextInt());\n    }\n\n    <span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-keyword\">int<\/span> i = <span class=\"hljs-number\">0<\/span>; i &lt; COUNT; i++) {\n      <span class=\"hljs-keyword\">int<\/span> number = numbers.getAtIndex(ValueLayout.JAVA_INT, i);\n      System.out.println(number);\n    }\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Kommen wir nun zu einem etwas komplizierterem Beispiel...<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"memorysegment-und-sequencelayout\">MemorySegment und SequenceLayout<\/h3>\n\n\n\n<p>Der folgende Code (Klasse <a href=\"https:\/\/github.com\/SvenWoltmann\/ffm-api-demo\/blob\/main\/src\/main\/java\/eu\/happycoders\/ffm\/FFMTestMultipleArrays.java\" target=\"_blank\" rel=\"noopener\">FFMTestMultipleArrays<\/a>) definiert ein <code>MemoryLayout<\/code> f\u00fcr ein Array von Integern und allokiert vier solche Arrays.<\/p>\n\n\n\n<p>Um die Elemente des Arrays zu schreiben, wird f\u00fcr <code>arrayLayout<\/code> ein <code>VarHandle<\/code> definiert. Das Argument <code>PathElement.sequenceElement()<\/code> gibt dabei an, dass wir f\u00fcr den Zugriff auf das Array \u00fcber das <code>VarHandle<\/code> den Index des jeweiligen Elements angeben wollen. Schlie\u00dflich schreiben wir die Array-Elemente mit <code>VarHandle.set(...)<\/code> und geben dabei als Argumente das Segment, den Offset (die Gr\u00f6\u00dfe des Array-Layouts multipliziert mit dem Index des Arrays, das wir gerade schreiben), den Index innerhalb des Arrays und den zu schreibenden Wert an.<\/p>\n\n\n\n<p>Auslesen k\u00f6nnten wir die Werte mit einer analogen <code>VarHandle.get(...)<\/code>-Methode, doch ich m\u00f6chte dir eine andere Variante zeigen: \u00dcber <code>MemorySegment.elements(...)<\/code> erzeugen wir einen Stream von Speichersegmenten, die jeweils ein Array enthalten. \u00dcber <code>MemorySegment.toArray(...)<\/code> laden wir das jeweilige Array aus dem Speichersegment.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">FFMTestMultipleArrays<\/span> <\/span>{\n  <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-keyword\">int<\/span> ARRAY_LENGTH = <span class=\"hljs-number\">8<\/span>;\n  <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-keyword\">int<\/span> NUMBER_OF_ARRAYS = <span class=\"hljs-number\">4<\/span>;\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">(String&#091;] args)<\/span> <\/span>{\n    SequenceLayout arrayLayout = MemoryLayout.sequenceLayout(ARRAY_LENGTH, JAVA_INT);\n    VarHandle arrayHandle = arrayLayout.varHandle(PathElement.sequenceElement());\n\n    MemorySegment segment = Arena.global().allocate(arrayLayout, NUMBER_OF_ARRAYS);\n\n    ThreadLocalRandom random = ThreadLocalRandom.current();\n    <span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-keyword\">int<\/span> i = <span class=\"hljs-number\">0<\/span>; i &lt; NUMBER_OF_ARRAYS; i++) {\n      <span class=\"hljs-keyword\">long<\/span> offset = i * arrayLayout.byteSize();\n      <span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-keyword\">int<\/span> j = <span class=\"hljs-number\">0<\/span>; j &lt; ARRAY_LENGTH; j++) {\n        arrayHandle.set(segment, offset, j, random.nextInt(<span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">1000<\/span>));\n      }\n    }\n\n    segment\n        .elements(arrayLayout)\n        .forEach(\n            arraySegment -&gt; {\n              <span class=\"hljs-keyword\">int<\/span>&#091;] array = arraySegment.toArray(JAVA_INT);\n              System.out.println(Arrays.toString(array));\n            });\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Kommen wir zuletzt zu einem besonders komplizierterem Beispiel...<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"memorysegment-und-structlayout\">MemorySegment und StructLayout<\/h3>\n\n\n\n<p>Das letzte Beispiel (Klasse <a href=\"https:\/\/github.com\/SvenWoltmann\/ffm-api-demo\/blob\/main\/src\/main\/java\/eu\/happycoders\/ffm\/FFMTestArrayOfStructs.java\" target=\"_blank\" rel=\"noopener\">FFMTestArrayOfStructs<\/a>) definiert ein <code>StructLayout<\/code>, das aus den Komponenten <code>year<\/code>, <code>month<\/code> und <code>day<\/code>, jeweils vom Typ <code>short<\/code> besteht.<\/p>\n\n\n\n<p>Es definiert zus\u00e4tzlich ein <code>SequenceLayout<\/code> f\u00fcr ein Array von Datum-Structs.<\/p>\n\n\n\n<p>Danach definieren wir VarHandles f\u00fcr die Struct-Elemente <em>innerhalb<\/em> des Arrays. Wir m\u00fcssen dazu jeweils zwei Pfadelemente angeben: zuerst den Array-Index und danach den jeweiligen Elementnamen des Structs.<\/p>\n\n\n\n<p>Wir schreiben die Structs \u00fcber <code>VarHandle.set(...)<\/code> und geben als Argumente das Segment, den Offset 0 (da das Memory-Segment nur <em>ein<\/em> Element enth\u00e4lt, n\u00e4mlich das Array von Structs), den Array-Index und den zu schreibenden Wert an.<\/p>\n\n\n\n<p>Auslesen wollen wir die Structs \u00fcber <code>MemorySegment.elements(...)<\/code> wie im vorherigen Beispiel. Diese Methode liefert einen Stream von Memory Segmenten, die jeweils einen Struct enthalten. Die Elemente der Structs laden wir schlie\u00dflich \u00fcber drei weitere VarHandles f\u00fcr den Struct (die zuvor erstellten VarHandles waren f\u00fcr Structs <em>innerhalb eines Arrays<\/em>).<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">FFMTestArrayOfStructs<\/span> <\/span>{\n  <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-keyword\">int<\/span> ARRAY_LENGTH = <span class=\"hljs-number\">8<\/span>;\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">(String&#091;] args)<\/span> <\/span>{\n    StructLayout dateLayout =\n        MemoryLayout.structLayout(\n            ValueLayout.JAVA_SHORT.withName(<span class=\"hljs-string\">\"year\"<\/span>),\n            ValueLayout.JAVA_SHORT.withName(<span class=\"hljs-string\">\"month\"<\/span>),\n            ValueLayout.JAVA_SHORT.withName(<span class=\"hljs-string\">\"day\"<\/span>));\n\n    SequenceLayout positionArrayLayout = \n        MemoryLayout.sequenceLayout(ARRAY_LENGTH, dateLayout);\n\n    MemorySegment segment = Arena.global().allocate(positionArrayLayout);\n    writeToSegment(segment, positionArrayLayout);\n    readFromSegment(segment, dateLayout);\n  }\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">writeToSegment<\/span><span class=\"hljs-params\">(\n      MemorySegment segment, SequenceLayout positionArrayLayout)<\/span> <\/span>{\n    VarHandle yearInArrayHandle =\n        positionArrayLayout.varHandle(\n            PathElement.sequenceElement(), PathElement.groupElement(<span class=\"hljs-string\">\"year\"<\/span>));\n    VarHandle monthInArrayHandle =\n        positionArrayLayout.varHandle(\n            PathElement.sequenceElement(), PathElement.groupElement(<span class=\"hljs-string\">\"month\"<\/span>));\n    VarHandle dayInArrayHandle =\n        positionArrayLayout.varHandle(\n            PathElement.sequenceElement(), PathElement.groupElement(<span class=\"hljs-string\">\"day\"<\/span>));\n\n    ThreadLocalRandom random = ThreadLocalRandom.current();\n    <span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-keyword\">int<\/span> i = <span class=\"hljs-number\">0<\/span>; i &lt; ARRAY_LENGTH; i++) {\n      yearInArrayHandle.set(segment, <span class=\"hljs-number\">0<\/span>, i, (<span class=\"hljs-keyword\">short<\/span>) random.nextInt(<span class=\"hljs-number\">1900<\/span>, <span class=\"hljs-number\">2100<\/span>));\n      monthInArrayHandle.set(segment, <span class=\"hljs-number\">0<\/span>, i, (<span class=\"hljs-keyword\">short<\/span>) random.nextInt(<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">13<\/span>));\n      dayInArrayHandle.set(segment, <span class=\"hljs-number\">0<\/span>, i, (<span class=\"hljs-keyword\">short<\/span>) random.nextInt(<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">31<\/span>));\n    }\n  }\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">readFromSegment<\/span><span class=\"hljs-params\">(MemorySegment segment, StructLayout dateLayout)<\/span> <\/span>{\n    VarHandle yearHandle = dateLayout.varHandle(PathElement.groupElement(<span class=\"hljs-string\">\"year\"<\/span>));\n    VarHandle monthHandle = dateLayout.varHandle(PathElement.groupElement(<span class=\"hljs-string\">\"month\"<\/span>));\n    VarHandle dayHandle = dateLayout.varHandle(PathElement.groupElement(<span class=\"hljs-string\">\"day\"<\/span>));\n\n    segment\n        .elements(dateLayout)\n        .forEach(\n            positionSegment -&gt; {\n              <span class=\"hljs-keyword\">int<\/span> year = (<span class=\"hljs-keyword\">int<\/span>) yearHandle.get(positionSegment, <span class=\"hljs-number\">0<\/span>);\n              <span class=\"hljs-keyword\">int<\/span> month = (<span class=\"hljs-keyword\">int<\/span>) monthHandle.get(positionSegment, <span class=\"hljs-number\">0<\/span>);\n              <span class=\"hljs-keyword\">int<\/span> day = (<span class=\"hljs-keyword\">int<\/span>) dayHandle.get(positionSegment, <span class=\"hljs-number\">0<\/span>);\n              System.out.printf(<span class=\"hljs-string\">\"%04d-%02d-%02d\\n\"<\/span>, year, month, day);\n            });\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-uagb-info-box uagb-block-76088612 uagb-infobox__content-wrap  uagb-infobox-icon-left uagb-infobox-left uagb-infobox-stacked-mobile uagb-infobox-image-valign-top hc-infobox\"><div class=\"uagb-ifb-icon-wrap\"><svg xmlns=\"https:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\"><path d=\"M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 128c17.67 0 32 14.33 32 32c0 17.67-14.33 32-32 32S224 177.7 224 160C224 142.3 238.3 128 256 128zM296 384h-80C202.8 384 192 373.3 192 360s10.75-24 24-24h16v-64H224c-13.25 0-24-10.75-24-24S210.8 224 224 224h32c13.25 0 24 10.75 24 24v88h16c13.25 0 24 10.75 24 24S309.3 384 296 384z\"><\/path><\/svg><\/div><div class=\"uagb-ifb-content\"><div class=\"uagb-ifb-title-wrap\"><\/div><p class=\"uagb-ifb-desc\"><code>VarHandle.get(\u2026)<\/code> hat eigentlich einen R\u00fcckgabewert vom Typ <code>Object<\/code>, ist aber mit <code>@MethodHandle.PolymorphicSignature<\/code> annotiert. Das bedeutet, dass die <code>get(\u2026)<\/code>-Methode im obigen Beispiel nicht zun\u00e4chst ein <code>Integer<\/code>-<em>Objekt<\/em> zur\u00fcckgibt, das dann in ein <code>int<\/code>-Primitiv unboxed wird, sondern direkt ein <code>int<\/code>-Pritimiv.<\/p><\/div><\/div>\n\n\n\n<p>Im GitHub-Repository findest du noch ein weiteres Beispiel, <a href=\"https:\/\/github.com\/SvenWoltmann\/ffm-api-demo\/blob\/main\/src\/main\/java\/eu\/happycoders\/ffm\/FFMTestArrayOfArrays.java\" target=\"_blank\" rel=\"noopener\">FFMTestArrayOfArrays<\/a>, das ich hier nicht mit abdrucke, da es keine neuen Konzepte einf\u00fchrt.<\/p>\n\n\n\n<p>Du hast nun ein solides Grundlagenwissen \u00fcber Arenen, Speichersegmente, Speicherlayouts und Funktionsdeskriptoren erworben. Damit solltest du bereit sein f\u00fcr erste Ausfl\u00fcge in die Welt der nativen Funktionen und des nativen Speichers.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"eine-kleine-geschichte-der-foreign-function-memory-api\">Eine kleine Geschichte der Foreign Function &amp; Memory API<\/h2>\n\n\n\n<p>Zum Abschluss findest du in diesem Abschnitt noch kurzen R\u00fcckblick auf die Entwicklungsschritte der FFM API.<\/p>\n\n\n\n<p>Bereits im M\u00e4rz 2020, in <a href=\"\/de\/java\/java-14-features\/#Foreign-Memory_Access_API_Incubator\">Java 14<\/a>, wurde die sogenannte \u201eForeign-Memory Access API\u201d im Incubator-Stadium vorgestellt (<a href=\"https:\/\/openjdk.org\/jeps\/370\" target=\"_blank\" rel=\"noopener\">JEP 370<\/a>).<\/p>\n\n\n\n<p>Ein Jahr sp\u00e4ter wurde in <a href=\"\/de\/java\/java-16-features\/#Foreign_Linker_API_Incubator_Foreign-Memory_Access_API_Third_Incubator\">Java 16<\/a> die \u201eForeign Linker API\u201d im Incubator-Stadium vorgestellt (<a href=\"https:\/\/openjdk.org\/jeps\/389\" target=\"_blank\" rel=\"noopener\">JEP 389<\/a>).<\/p>\n\n\n\n<p>In <a href=\"\/de\/java\/java-17-features\/#Foreign_Function_Memory_API_Incubator\">Java 17<\/a> wurden die beiden APIs zur \u201eForeign Function &amp; Memory API\u201d zusammengef\u00fchrt und diese vereinheitliche API noch einmal als Incubator-Version vorgelegt (<a href=\"https:\/\/openjdk.org\/jeps\/412\" target=\"_blank\" rel=\"noopener\">JEP 412<\/a>).<\/p>\n\n\n\n<p>In <a href=\"\/de\/java\/java-19-features\/#Foreign_Function_Memory_API_Preview_JEP_424\">Java 19<\/a> wurde die FFM API ins Preview-Stadium bef\u00f6rdert (<a href=\"https:\/\/openjdk.org\/jeps\/424\" target=\"_blank\" rel=\"noopener\">JEP 424<\/a>).<\/p>\n\n\n\n<p>In <a href=\"\/de\/java\/java-22-features\/\">Java 22<\/a> wurde die API im M\u00e4rz 2024 nach langer Entwicklungs- und Reifungszeit als produktionsreif deklariert und finalisiert (<a href=\"https:\/\/openjdk.org\/jeps\/454\" target=\"_blank\" rel=\"noopener\">JEP 454<\/a>).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"fazit\">Fazit<\/h2>\n\n\n\n<p>Die meisten Java-Entwicklerinnen und -Entwickler werden wahrscheinlich selten auf nativen Speicher zugreifen oder nativen Code ausf\u00fchren m\u00fcssen. Dennoch ist es hilfreich zu wissen, dass diese M\u00f6glichkeit existiert, z. B. um in anderen Sprachen geschriebene KI-Libraries aus Java heraus aufzurufen.<\/p>\n\n\n\n<p>In diesem Artikel hast du die Grundlagen daf\u00fcr gelernt. Falls du noch tiefer in die Materie einsteigen m\u00f6chtest, empfehle ich dir, <a href=\"https:\/\/openjdk.org\/jeps\/454\" target=\"_blank\" rel=\"noopener\">JDK Enhancement Proposal 454<\/a> und die Webseite von <a href=\"https:\/\/openjdk.org\/projects\/panama\/\" target=\"_blank\" rel=\"noopener\">Project Panama<\/a> zu studieren.<\/p>\n\n\n\n<p>Planst du bereits eine native Library anzubinden? Wenn ja, welche? Lass es mich \u00fcber die Kommentarfunktion wissen!<\/p>\n<aside><p>Wenn dir der Artikel weitergeholfen hat, w\u00fcrde ich mich sehr \u00fcber eine positive Bewertung auf meinem <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">ProvenExpert-Profil<\/a> freuen. Dein Feedback hilft mir, meine Inhalte weiter zu verbessern und motiviert mich, neue informative Artikel zu schreiben.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">Bewertung abgeben<\/a><\/p>\r\n                        <p>Du m\u00f6chtest \u00fcber alle neue Java-Features auf dem Laufenden sein? Dann <a href=\"#\" data-formkit-toggle=\"d8ee997126\">klicke hier<\/a>, um dich f\u00fcr den HappyCoders-Newsletter anzumelden.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"#\" data-formkit-toggle=\"d8ee997126\">Newsletter-Anmeldung<\/a><\/p><\/aside>","protected":false},"excerpt":{"rendered":"<p>Erfahre, wie du mit der Foreign Function &#038; Memory API aus Java heraus auf Bibliotheken anderer Programmiersprachen zugreifst.<\/p>\n","protected":false},"author":1,"featured_media":39036,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_titles_title":"","_seopress_titles_desc":"Erfahre, wie du mit der Foreign Function & Memory API aus Java heraus auf Bibliotheken anderer Programmiersprachen zugreifst.","_seopress_robots_index":"","_seopress_robots_follow":"","_seopress_robots_imageindex":"","_seopress_robots_snippet":"","_seopress_robots_primary_cat":"","_seopress_robots_breadcrumbs":"","_seopress_robots_freeze_modified_date":"","_seopress_robots_custom_modified_date":"","_seopress_robots_canonical":"","_seopress_social_fb_title":"","_seopress_social_fb_desc":"","_seopress_social_fb_img":"","_seopress_social_fb_img_attachment_id":0,"_seopress_social_fb_img_width":0,"_seopress_social_fb_img_height":0,"_seopress_social_twitter_title":"","_seopress_social_twitter_desc":"","_seopress_social_twitter_img":"","_seopress_social_twitter_img_attachment_id":0,"_seopress_social_twitter_img_width":0,"_seopress_social_twitter_img_height":0,"_seopress_redirections_value":"","_seopress_redirections_enabled":"","_seopress_redirections_enabled_regex":"","_seopress_redirections_logged_status":"","_seopress_redirections_param":"","_seopress_redirections_type":0,"_seopress_analysis_target_kw":"Foreign Function & Memory API,FFM API,Foreign-Function-Memory-API","_seopress_news_disabled":"","_seopress_video_disabled":"","_seopress_video":[],"_seopress_pro_schemas_manual":[],"_seopress_pro_rich_snippets_disable_all":"","_seopress_pro_rich_snippets_disable":[],"_seopress_pro_schemas":[],"_uag_custom_page_level_css":"","_wp_convertkit_post_meta":{"form":"-1","landing_page":"","tag":"0","restrict_content":"0"},"_metis_text_type":"standard","_metis_text_length":29565,"_post_count":0,"footnotes":""},"categories":[64],"tags":[165],"class_list":["post-39033","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java","tag-java-fortgeschritten"],"uagb_featured_image_src":{"full":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm.jpg",1770,986,false],"thumbnail":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm.jpg",150,84,false],"medium":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm.jpg",300,167,false],"medium_large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm.jpg",768,428,false],"large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm.jpg",1024,570,false],"feature_thumb_224":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm-224x125.jpg",224,125,true],"feature_thumb_336":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm-336x187.jpg",336,187,true],"feature_thumb_504":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm-504x281.jpg",504,281,true],"feature_thumb_672":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm-672x374.jpg",672,374,true],"half_400":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm-400x223.jpg",400,223,true],"half_600":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm-600x334.jpg",600,334,true],"full_800":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm-800x446.jpg",800,446,true],"full_944":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm-944x526.jpg",944,526,true],"full_1200":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm-1200x668.jpg",1200,668,true],"wide_1180":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm-1180x490.jpg",1180,490,true],"wide_1770":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm-1770x735.jpg",1770,735,true],"1536x1536":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm.jpg",1536,856,false],"2048x2048":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2023\/12\/java-foreign-function-and-memory-api-ffm.jpg",1770,986,false]},"uagb_author_info":{"display_name":"Sven Woltmann","author_link":"https:\/\/www.happycoders.eu\/de\/author\/sven\/"},"uagb_comment_info":0,"uagb_excerpt":"Erfahre, wie du mit der Foreign Function & Memory API aus Java heraus auf Bibliotheken anderer Programmiersprachen zugreifst.","public_identification_id":"1ab9cf69609e496ca9cc4c0f67f7f902","private_identification_id":"b9bf5f8076014b1a81c95a749e037083","_links":{"self":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/39033","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/comments?post=39033"}],"version-history":[{"count":10,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/39033\/revisions"}],"predecessor-version":[{"id":52419,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/39033\/revisions\/52419"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media\/39036"}],"wp:attachment":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media?parent=39033"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/categories?post=39033"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/tags?post=39033"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}