<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
我們知道在native的程式碼中有很多指標,這些指標在JNA中被對映成為Pointer。除了Pointer之外,JNA還提供了更加強大的Memory類,本文將會一起探討JNA中的Pointer
和Memory
的使用。
Pointer是JNA中引入的類,用來表示native方法中的指標。大家回想一下native方法中的指標到底是什麼呢?
native方法中的指標實際上就是一個地址,這個地址就是真正物件的記憶體地址。所以在Pointer中定義了一個peer屬性,用來儲存真正物件的記憶體地址:
protected long peer;
實時上,Pointer的建構函式就需要傳入這個peer引數:
public Pointer(long peer) { this.peer = peer; }
接下來我們看一下如何從Pointer中取出一個真正的物件,這裡以byte陣列為例:
public void read(long offset, byte[] buf, int index, int length) { Native.read(this, this.peer, offset, buf, index, length); }
實際上這個方法呼叫了Native.read方法,我們繼續看一下這個read方法:
static native void read(Pointer pointer, long baseaddr, long offset, byte[] buf, int index, int length);
可以看到它是一個真正的native方法,用來讀取一個指標物件。
除了Byte陣列之外,Pointer還提供了很多其他型別的讀取方法。
又讀取就有寫入,我們再看下Pointer是怎麼寫入資料的:
public void write(long offset, byte[] buf, int index, int length) { Native.write(this, this.peer, offset, buf, index, length); }
同樣的,還是呼叫 Native.write
方法來寫入資料。
這裡Native.write方法也是一個native方法:
static native void write(Pointer pointer, long baseaddr, long offset, byte[] buf, int index, int length);
Pointer還提供了很多其他型別資料的寫入方法。
當然還有更加直接的get*方法:
public byte getByte(long offset) { return Native.getByte(this, this.peer, offset); }
在Pointer中,還有兩個createConstant方法,用來建立不可讀也不可寫的Pointer:
public static final Pointer createConstant(long peer) { return new Opaque(peer); } public static final Pointer createConstant(int peer) { return new Opaque((long)peer & 0xFFFFFFFF); }
實際上返回的而是Opaque類,這個類繼承自Pointer,但是它裡面的所有read或者write方法,都會丟擲UnsupportedOperationException
:
private static class Opaque extends Pointer { private Opaque(long peer) { super(peer); } @Override public Pointer share(long offset, long size) { throw new UnsupportedOperationException(MSG); }
Pointer是基本的指標對映,如果對於通過使用native的malloc方法分配的記憶體空間而言,除了Pointer指標的開始位置之外,我們還需要知道分配的空間大小。所以一個簡單的Pointer是不夠用了。
這種情況下,我們就需要使用Memory。
Memory是一種特殊的Pointer, 它儲存了分配出來的空間大小。
我們來看一下Memory的定義和它裡面包含的屬性:
public class Memory extends Pointer { ... private static ReferenceQueue<Memory> QUEUE = new ReferenceQueue<Memory>(); private static LinkedReference HEAD; // the head of the doubly linked list used for instance tracking private static final WeakMemoryHolder buffers = new WeakMemoryHolder(); private final LinkedReference reference; // used to track the instance protected long size; // Size of the malloc'ed space ... }
Memory裡面定義了5個資料,我們接下來一一進行介紹。
首先是最為重要的size,size表示的是Memory中記憶體空間的大小,我們來看下Memory的建構函式:
public Memory(long size) { this.size = size; if (size <= 0) { throw new IllegalArgumentException("Allocation size must be greater than zero"); } peer = malloc(size); if (peer == 0) throw new OutOfMemoryError("Cannot allocate " + size + " bytes"); reference = LinkedReference.track(this); }
可以看到Memory型別的資料需要傳入一個size引數,表示Memory佔用的空間大小。當然,這個size必須要大於0.
然後呼叫native方法的malloc方法來分配一個記憶體空間,返回的peer儲存的是記憶體空間的開始地址。如果peer==0,表示分配失敗。
如果分配成功,則將當前Memory儲存到LinkedReference中,用來跟蹤當前的位置。
我們可以看到Memory中有兩個LinkedReference,一個是HEAD,一個是reference。
LinkedReference
本身是一個WeakReference
,weekReference參照的物件只要垃圾回收執行,就會被回收,而不管是否記憶體不足。
private static class LinkedReference extends WeakReference<Memory>
我們看一下LinkedReference的建構函式:
private LinkedReference(Memory referent) { super(referent, QUEUE); }
這個QUEUE是ReferenceQueue,表示的是GC待回收的物件列表。
我們看到Memory的建構函式除了設定size之外,還呼叫了:
reference = LinkedReference.track(this);
仔細看LinkedReference.track方法:
static LinkedReference track(Memory instance) { // use a different lock here to allow the finialzier to unlink elements too synchronized (QUEUE) { LinkedReference stale; // handle stale references here to avoid GC overheating when memory is limited while ((stale = (LinkedReference) QUEUE.poll()) != null) { stale.unlink(); } } // keep object allocation outside the syncronized block LinkedReference entry = new LinkedReference(instance); synchronized (LinkedReference.class) { if (HEAD != null) { entry.next = HEAD; HEAD = HEAD.prev = entry; } else { HEAD = entry; } } return entry; }
這個方法的意思是首先從QUEUE中拿出那些準備被垃圾回收的Memory物件,然後將其從LinkedReference中unlink。 最後將新建立的物件加入到LinkedReference中。
因為Memory中的QUEUE和HEAD都是類變數,所以這個LinkedReference
儲存的是JVM中所有的Memory物件。
最後Memory中也提供了對應的read和write方法,但是Memory中的方法和Pointer不同,Memory中的方法多了一個boundsCheck,如下所示:
public void read(long bOff, byte[] buf, int index, int length) { boundsCheck(bOff, length * 1L); super.read(bOff, buf, index, length); } public void write(long bOff, byte[] buf, int index, int length) { boundsCheck(bOff, length * 1L); super.write(bOff, buf, index, length); }
為什麼會有boundsCheck呢?這是因為Memory和Pointer不同,Memory中有一個size的屬性,用來儲存分配的記憶體大小。使用boundsCheck就是來判斷存取的地址是否出界,用來保證程式的安全。
Pointer和Memory算是JNA中的高階功能,大家如果想要和native的alloc方法進行對映的話,就要考慮使用了。
到此這篇關於java 之JNA中的Memory和Pointer的使用方法的文章就介紹到這了,更多相關 Memory和Pointer內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45