成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

可輕松管理大內(nèi)存,JDK14外部?jī)?nèi)存訪問(wèn)API探秘

存儲(chǔ) 存儲(chǔ)軟件
外部?jī)?nèi)存訪問(wèn) API 是 Project Panama (1) 的一部分,是對(duì) ByteBuffer 的替代,而 ByteBuffer 之前是用于堆外內(nèi)存。對(duì)于任何低級(jí)的 I/O 來(lái)說(shuō),堆外內(nèi)存是需要的,因?yàn)樗苊饬?GC,從而比堆內(nèi)內(nèi)存訪問(wèn)更快、更可靠。

[[321267]]

 隨著 JDK 14 的發(fā)布,新版帶來(lái)了很多全新或預(yù)覽的功能,如 instanceof 模式匹配、信息量更多的 NullPointerExceptions、switch 表達(dá)式等。大部分功能已經(jīng)被許多新聞和博客網(wǎng)站廣泛報(bào)道,但是孵化中的外部?jī)?nèi)存訪問(wèn) API 還沒(méi)有得到那么多的報(bào)道,許多報(bào)道 JDK 14 的新聞都省略了它,或者只提到了 1-2 行。很可能沒(méi)有多少人知道它,也不知道它最終會(huì)允許你在 Java 中做什么。

簡(jiǎn)而言之,外部?jī)?nèi)存訪問(wèn) API 是 Project Panama (1) 的一部分,是對(duì) ByteBuffer 的替代,而 ByteBuffer 之前是用于堆外內(nèi)存。對(duì)于任何低級(jí)的 I/O 來(lái)說(shuō),堆外內(nèi)存是需要的,因?yàn)樗苊饬?GC,從而比堆內(nèi)內(nèi)存訪問(wèn)更快、更可靠。但是,ByteBuffer 也存在局限,比如 2GB 的大小限制等。

如果你想了解更多,你可以在下面鏈接觀看 Maurizio Cimadamore 的演講 (2)。

正如上面的視頻所描述的那樣,孵化外部?jī)?nèi)存訪問(wèn) API 并不是最終的目標(biāo),而是通往更高的目標(biāo):Java 中的原生 C 庫(kù)訪問(wèn)。遺憾的是,目前還沒(méi)有關(guān)于何時(shí)交付的時(shí)間表。

話雖如此,如果你想嘗試真正的好東西,那么你可以從 Github (3) 中構(gòu)建自己的 JDK。我一直在做這個(gè)工作,為我的超頻工具所需要的各種 Nvidia API 做綁定,這些 API 利用 Panama 的抽象層來(lái)使事情變得更簡(jiǎn)單。

說(shuō)了這么多,那你實(shí)際是怎么使用它的呢?

MemoryAddress 以及 MemorySegment

Project Panama 中的兩個(gè)主要接口是 MemoryAddress 和 MemorySegment。在外部?jī)?nèi)存訪問(wèn) API 中,獲取 MemoryAddress 首先需要使用靜態(tài)的 allocateNative() 方法創(chuàng)建一個(gè) MemorySegment,然后獲取該段的基本地址。

 

  1. import jdk.incubator.foreign.MemoryAddress; 
  2. import jdk.incubator.foreign.MemorySegment; 
  3. public class PanamaMain 
  4.     public static void main(String[] args) 
  5.         MemoryAddress address = MemorySegment.allocateNative(4).baseAddress(); 
  6.     } 

當(dāng)然,你可以通過(guò) MemoryAddress 的 segment() 方法再次獲取同一個(gè) MemoryAddress 的段。在上面的例子中,我們使用的是重載的 allocateNative() 方法,該方法接收了一個(gè)新的 MemorySegment 的字節(jié)大小的 long 值。這個(gè)方法還有另外兩個(gè)版本,一個(gè)是接受一個(gè) MemoryLayout,我稍后會(huì)講到,另一個(gè)是接受一個(gè)以字節(jié)為單位的大小和字節(jié)對(duì)齊。

MemoryAddress 本身并沒(méi)有太多的API。唯一值得注意的方法是 segment() 和 offset() 。沒(méi)有獲取 MemoryAddress 的原始地址的方法。

而 MemorySegment 則有更多的 API。你可以通過(guò) asByteBuffer() 將 MemorySegment 轉(zhuǎn)換為 ByteBuffer,通過(guò) close() 關(guān)閉(讀:free)段(來(lái)自 AutoClosable 接口),然后用 asSlice() 將其切片(后面會(huì)有更多的內(nèi)容)。

好了,我們已經(jīng)分配了一大塊內(nèi)存,但如何對(duì)它進(jìn)行讀寫呢?

MemoryHandle

MemoryHandles 是一個(gè)提供 VarHandles 的類,用于讀寫內(nèi)存值。它提供了一些靜態(tài)的方法來(lái)獲取 VarHandle,但主要的方法是 varHandle,它接受下面任一類。

  • byte.class
  • short.class
  • char.class
  • int.class
  • double.class
  • long.class

(這些都不能和Object版本混淆,比如Integer.class)

在大多數(shù)情況下,你只需要通過(guò) nativeOrder() 來(lái)使用原生順序。至于你使用的類,你要使用一個(gè)適合 MemorySegment 的字節(jié)大小的類,所以在上面的例子中是 int.class,因?yàn)樵?Java 中 int 占用了 4 個(gè)字節(jié)。

一旦你創(chuàng)建了一個(gè) VarHandle,你現(xiàn)在就可以用它來(lái)讀寫內(nèi)存了。讀取是通過(guò) VarHandle 的各種 get() 方法來(lái)完成的。關(guān)于這些 get 方法的文檔并不是很有用,但簡(jiǎn)單的說(shuō)就是你把 MemoryAddress 實(shí)例傳遞給 get 方法,就像這樣。

 

  1. import java.lang.invoke.VarHandle; 
  2. import java.nio.ByteOrder; 
  3. import jdk.incubator.foreign.MemoryAddress; 
  4. import jdk.incubator.foreign.MemoryHandles; 
  5. import jdk.incubator.foreign.MemorySegment; 
  6. public class PanamaMain 
  7.     public static void main(String[] args) 
  8.     { 
  9.         MemoryAddress address = MemorySegment.allocateNative(4).baseAddress(); 
  10.  
  11.         VarHandle handle = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder()); 
  12.  
  13.         int value = (int)handle.get(address); 
  14.  
  15.         System.out.println("Memory Value: " + value); 
  16.     }  

你會(huì)注意到,這里的 VarHandle 返回的值是類型化的。如果你以前使用過(guò) VarHandles,這對(duì)你來(lái)說(shuō)并不震驚,但如果你沒(méi)有使用過(guò) VarHandle,那么你只要知道這很正常,因?yàn)?VarHandle 實(shí)例返回的是 Object。

默認(rèn)情況下,所有由異構(gòu)內(nèi)存訪問(wèn) API 分配的內(nèi)存都是零。這一點(diǎn)很好,因?yàn)槟悴粫?huì)在內(nèi)存中留下隨機(jī)的垃圾,但對(duì)于性能關(guān)鍵的情況下可能是不好的。

至于設(shè)置一個(gè)值,你可以使用 set() 方法。就像 get() 方法一樣,你要傳遞地址,然后是你想傳遞到內(nèi)存中的值。

 

  1. import java.lang.invoke.VarHandle; 
  2. import java.nio.ByteOrder; 
  3. import jdk.incubator.foreign.MemoryAddress; 
  4. import jdk.incubator.foreign.MemoryHandles; 
  5. import jdk.incubator.foreign.MemorySegment; 
  6. public class PanamaMain 
  7.     public static void main(String[] args) 
  8.     { 
  9.         MemoryAddress address = MemorySegment.allocateNative(4).baseAddress(); 
  10.  
  11.         VarHandle handle = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder()); 
  12.  
  13.         handle.set(address, 10); 
  14.  
  15.         int value = (int)handle.get(address); 
  16.  
  17.         System.out.println("Memory Value: " + value); 
  18.     }   

MemoryLayout 以及 MemoryLayouts

MemoryLayouts 類提供了 MemoryLayout 接口的預(yù)定義實(shí)現(xiàn)。這些接口允許你快速分配 MemorySegments,保證分配等效類型的 MemorySegments,比如 Java int。一般來(lái)說(shuō),使用這些預(yù)定義的布局比分配大塊內(nèi)存要容易得多,因?yàn)樗鼈兲峁┝四阆胍褂玫某S貌季诸愋停恍枰檎宜鼈兊拇笮 ?/p>

 

  1. import java.lang.invoke.VarHandle; 
  2. import java.nio.ByteOrder; 
  3. import jdk.incubator.foreign.MemoryAddress; 
  4. import jdk.incubator.foreign.MemoryHandles; 
  5. import jdk.incubator.foreign.MemoryLayouts; 
  6. import jdk.incubator.foreign.MemorySegment; 
  7. public class PanamaMain 
  8.     public static void main(String[] args) 
  9.     { 
  10.         MemoryAddress address = MemorySegment.allocateNative(MemoryLayouts.JAVA_INT).baseAddress(); 
  11.  
  12.         VarHandle handle = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder()); 
  13.  
  14.         handle.set(address, 10); 
  15.  
  16.         int value = (int)handle.get(address); 
  17.  
  18.         System.out.println("Memory Value: " + value); 
  19.     }   

如果你不想使用這些預(yù)定義的布局,你也不必這樣做。MemoryLayout(注意沒(méi)有 "s")有靜態(tài)方法,允許你創(chuàng)建自己的布局。這些方法會(huì)返回一些擴(kuò)展接口,例如:

  • ValueLayout
  • SequenceLayout
  • GroupLayout

ValueLayout 接口的實(shí)現(xiàn)是由 ofValueBits() 方法返回的。它所做的就是創(chuàng)建一個(gè)基本的單值 MemoryLayout,就像 MemoryLayouts.JAVA_INT 一樣。

SequenceLayout 是用于創(chuàng)建一個(gè)像數(shù)組一樣的 MemoryLayout 的序列。接口實(shí)現(xiàn)是通過(guò)兩個(gè)靜態(tài)的 ofSequence() 方法返回,不過(guò)只有指定長(zhǎng)度的方法可以用來(lái)分配內(nèi)存。

GroupLayout 用于結(jié)構(gòu)和聯(lián)合類型的內(nèi)存分配,因?yàn)樗鼈冎g相當(dāng)相似。它們的接口實(shí)現(xiàn)來(lái)自于 structs 的 ofStruct() 或 union 的 ofUnion()。

如果之前沒(méi)有說(shuō)清楚,MemoryLayout(s) 的使用完全是可選的,但是,它們使 API 的使用和調(diào)試變得更容易,因?yàn)槟憧梢杂贸A棵孀x取原始數(shù)字。

但是,它們也有自己的問(wèn)題。任何接受 var args MemoryLayout 輸入作為方法或構(gòu)造函數(shù)的一部分的東西都會(huì)接受 GroupLayout 或其他 MemoryLayout,而不是預(yù)期的輸入。請(qǐng)確保你指定了正確的布局。

切片和數(shù)組

MemorySegment 可以被切片,以便在一個(gè)內(nèi)存塊中存儲(chǔ)多個(gè)值,在處理數(shù)組、結(jié)構(gòu)和聯(lián)合時(shí)常用。如上文所述,這是通過(guò) asSlice() 方法來(lái)完成的。為了進(jìn)行分片,你需要知道你要分片的 MemorySegment 的起始位置,單位是字節(jié),以及存儲(chǔ)在該位置的值的大小,單位是字節(jié)。這將返回一個(gè) MemorySegment,然后你可以獲得 MemoryAddress。

 

  1. import java.lang.invoke.VarHandle; 
  2. import java.nio.ByteOrder; 
  3. import jdk.incubator.foreign.MemoryAddress; 
  4. import jdk.incubator.foreign.MemoryHandles; 
  5. import jdk.incubator.foreign.MemorySegment; 
  6. public class PanamaMain 
  7.     public static void main(String[] args) 
  8.     { 
  9.         MemoryAddress address = MemorySegment.allocateNative(24).baseAddress(); 
  10.          
  11.         MemoryAddress address1 = address.segment().asSlice(0, 8).baseAddress(); 
  12.         MemoryAddress address2 = address.segment().asSlice(8, 8).baseAddress(); 
  13.         MemoryAddress address3 = address.segment().asSlice(16, 8).baseAddress(); 
  14.          
  15.         VarHandle handle = MemoryHandles.varHandle(long.class, ByteOrder.nativeOrder()); 
  16. handle.set(address1, Long.MIN_VALUE); 
  17.         handle.set(address2, 0); 
  18.         handle.set(address3, Long.MAX_VALUE); 
  19.          
  20.         long value1 = (long)handle.get(address1); 
  21.         long value2 = (long)handle.get(address2); 
  22.         long value3 = (long)handle.get(address3); 
  23.          
  24.          
  25.         System.out.println("Memory Value 1: " + value1); 
  26.         System.out.println("Memory Value 2: " + value2); 
  27.         System.out.println("Memory Value 3: " + value3); 
  28.     }   

這里需要指出的是,你不需要為每個(gè) MemoryAddress 創(chuàng)建新的 VarHandles。

在一個(gè) 24 字節(jié)的內(nèi)存塊中,我們把它分成了 3 個(gè)不同的切片,使之成為一個(gè)數(shù)組。

你可以使用一個(gè) for 循環(huán)來(lái)迭代它,而不是硬編碼分片值。

 

  1. import java.lang.invoke.VarHandle; 
  2. import java.nio.ByteOrder; 
  3. import jdk.incubator.foreign.MemoryAddress; 
  4. import jdk.incubator.foreign.MemoryHandles; 
  5. import jdk.incubator.foreign.MemorySegment; 
  6. public class PanamaMain 
  7.     public static void main(String[] args) 
  8.     { 
  9.         MemoryAddress address = MemorySegment.allocateNative(24).baseAddress(); 
  10.          
  11.         VarHandle handle = MemoryHandles.varHandle(long.class, ByteOrder.nativeOrder()); 
  12.          
  13.         for(int i = 0; i <= 2; i++) 
  14.         { 
  15.             MemoryAddress slice = address.segment().asSlice(i*8, 8).baseAddress(); 
  16.              
  17.             handle.set(slice, i*8); 
  18.              
  19.             System.out.println("Long slice at location " + handle.get(slice)); 
  20.         } 
  21.     }   

當(dāng)然,你可以使用 SequenceLayout 而不是使用原始的、硬編碼的值。

 

  1. import java.lang.invoke.VarHandle; 
  2. import java.nio.ByteOrder; 
  3. import jdk.incubator.foreign.MemoryAddress; 
  4. import jdk.incubator.foreign.MemoryHandles; 
  5. import jdk.incubator.foreign.MemoryLayout; 
  6. import jdk.incubator.foreign.MemoryLayouts; 
  7. import jdk.incubator.foreign.MemorySegment; 
  8. import jdk.incubator.foreign.SequenceLayout; 
  9. public class PanamaMain 
  10.     public static void main(String[] args) 
  11.     { 
  12.         SequenceLayout layout = MemoryLayout.ofSequence(3, MemoryLayouts.JAVA_LONG); 
  13.         MemoryAddress address = MemorySegment.allocateNative(layout).baseAddress(); 
  14.          
  15.         VarHandle handle = MemoryHandles.varHandle(long.class, ByteOrder.nativeOrder()); 
  16.          
  17.         for(int i = 0; i < layout.elementCount().getAsLong(); i++) 
  18.         { 
  19.             MemoryAddress slice = address.segment().asSlice(i*layout.elementLayout().byteSize(), layout.elementLayout().byteSize()).baseAddress(); 
  20.              
  21.             handle.set(slice, i*layout.elementLayout().byteSize()); 
  22.              
  23.             System.out.println("Long slice at location " + handle.get(slice)); 
  24.         } 
  25.     }   

不包括的內(nèi)容

到目前為止,所有的東西都只在 JDK 14 的孵化版的范圍內(nèi),然而,正如前面提到的,這一切都是邁向原生 C 庫(kù)訪問(wèn)的墊腳石,甚至有一兩個(gè)方法名被更改了,已經(jīng)過(guò)時(shí)了。在這一切的基礎(chǔ)上,還有另外一層終于可以讓你訪問(wèn)原生庫(kù)調(diào)用。總結(jié)一下還缺什么。

  • jextract
  • Library 查找
  • ABI specific ValueLayout
  • Runtime ABI 布局
  • FunctionDescriptor 接口
  • ForeignUnsafe

所有這些都是在外部訪問(wèn) API 的基礎(chǔ)上分層,也是對(duì)外存訪問(wèn) API 的補(bǔ)充。如果你打算為一些原生 C 語(yǔ)言庫(kù)創(chuàng)建綁定,那么現(xiàn)在學(xué)習(xí)這些 API 就不會(huì)浪費(fèi)。

文中鏈接

  1. https://openjdk.java.net/projects/panama/
  2. https://www.youtube.com/watch?v=r4dNRVWYaZI
  3. https://github.com/openjdk/panama-foreign

原文

https://medium.com/@youngty1997/jdk-14-foreign-memory-access-api-overview-70951fe221c9

本文轉(zhuǎn)載自微信公眾號(hào)「高可用架構(gòu)」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系高可用架構(gòu)公眾號(hào)。

 

 

 

責(zé)任編輯:武曉燕 來(lái)源: 高可用架構(gòu)
相關(guān)推薦

2025-06-13 08:34:38

2021-09-05 06:00:47

電腦內(nèi)存Windows

2010-09-25 09:56:46

JVM最大內(nèi)存

2021-04-30 20:20:36

HugePages大內(nèi)存頁(yè)系統(tǒng)

2018-07-23 09:26:08

iOS內(nèi)存優(yōu)化

2013-10-11 17:32:18

Linux運(yùn)維內(nèi)存管理

2024-11-18 11:49:51

2024-04-08 07:27:02

JDK8ZGC垃圾回收

2024-07-26 10:23:52

2010-09-17 14:04:14

JVM內(nèi)存設(shè)置

2010-04-23 11:18:05

Ubuntu 10.0

2025-05-27 02:45:45

2023-10-18 13:31:00

Linux內(nèi)存

2011-03-17 16:51:51

SQLServer數(shù)據(jù)加速劑

2018-10-19 09:51:05

服務(wù)器內(nèi)存RAM

2013-10-12 13:01:51

Linux運(yùn)維內(nèi)存管理

2009-02-09 08:55:12

ArcGIS API發(fā)布Silverlight

2019-07-10 05:08:05

CPU內(nèi)存分頁(yè)管理

2018-12-06 12:58:50

CPU內(nèi)存模塊

2011-07-20 17:04:43

Objective-C 內(nèi)存 內(nèi)存泄露
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 天天天天天天操 | 成人免费看片网 | 国产美女在线精品免费 | 欧美激情久久久久久 | 久久久青草婷婷精品综合日韩 | 一级毛片在线播放 | 青青草华人在线视频 | 午夜激情一区 | 午夜国产 | 亚洲欧美激情精品一区二区 | 在线观看亚 | 色综合天天网 | 国产91色在线 | 亚洲 | 欧美日本一区二区 | 亚洲国产欧美日韩 | 97国产精品视频人人做人人爱 | 欧美久久一级 | 久久亚洲一区二区三 | 一区二区三区四区国产 | 国产人成在线观看 | 中文在线一区二区 | 欧美一级在线 | 黄色大全免费看 | 我要看免费一级毛片 | 波多野结衣二区 | 欧美精品一区二区在线观看 | 精品成人免费视频 | 亚洲三级在线观看 | 91免费观看国产 | 成人国产在线视频 | 久久影院一区 | 欧美黄a | 日韩一区二区三区精品 | 蜜桃官网 | 伊人热久久 | 中文字幕国产高清 | 99在线精品视频 | 91精品久久久 | 插插插干干干 | 欧美日韩三级视频 | 视频一区在线 |