溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JNA中的Memory和Pointer怎么使用

發(fā)布時(shí)間:2022-04-19 10:39:01 來(lái)源:億速云 閱讀:384 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要講解了“JNA中的Memory和Pointer怎么使用”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“JNA中的Memory和Pointer怎么使用”吧!

簡(jiǎn)介

我們知道在native的代碼中有很多指針,這些指針在JNA中被映射成為Pointer。

Pointer

Pointer是JNA中引入的類(lèi),用來(lái)表示native方法中的指針。大家回想一下native方法中的指針到底是什么呢?

native方法中的指針實(shí)際上就是一個(gè)地址,這個(gè)地址就是真正對(duì)象的內(nèi)存地址。所以在Pointer中定義了一個(gè)peer屬性,用來(lái)存儲(chǔ)真正對(duì)象的內(nèi)存地址:

protected long peer;

實(shí)時(shí)上,Pointer的構(gòu)造函數(shù)就需要傳入這個(gè)peer參數(shù):

public Pointer(long peer) {
        this.peer = peer;
    }

接下來(lái)我們看一下如何從Pointer中取出一個(gè)真正的對(duì)象,這里以byte數(shù)組為例:

    public void read(long offset, byte[] buf, int index, int length) {
        Native.read(this, this.peer, offset, buf, index, length);
    }

實(shí)際上這個(gè)方法調(diào)用了Native.read方法,我們繼續(xù)看一下這個(gè)read方法:

static native void read(Pointer pointer, long baseaddr, long offset, byte[] buf, int index, int length);

可以看到它是一個(gè)真正的native方法,用來(lái)讀取一個(gè)指針對(duì)象。

除了Byte數(shù)組之外,Pointer還提供了很多其他類(lèi)型的讀取方法。

又讀取就有寫(xiě)入,我們?cè)倏聪翽ointer是怎么寫(xiě)入數(shù)據(jù)的:

    public void write(long offset, byte[] buf, int index, int length) {
        Native.write(this, this.peer, offset, buf, index, length);
    }

同樣的,還是調(diào)用 Native.write方法來(lái)寫(xiě)入數(shù)據(jù)。

這里Native.write方法也是一個(gè)native方法:

static native void write(Pointer pointer, long baseaddr, long offset, byte[] buf, int index, int length);

Pointer還提供了很多其他類(lèi)型數(shù)據(jù)的寫(xiě)入方法。

當(dāng)然還有更加直接的get*方法:

public byte getByte(long offset) {
        return Native.getByte(this, this.peer, offset);
    }

特殊的Pointer:Opaque

在Pointer中,還有兩個(gè)createConstant方法,用來(lái)創(chuàng)建不可讀也不可寫(xiě)的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);
    }

實(shí)際上返回的而是Opaque類(lèi),這個(gè)類(lèi)繼承自Pointer,但是它里面的所有read或者write方法,都會(huì)拋出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);
        }

Memory

Pointer是基本的指針映射,如果對(duì)于通過(guò)使用native的malloc方法分配的內(nèi)存空間而言,除了Pointer指針的開(kāi)始位置之外,我們還需要知道分配的空間大小。所以一個(gè)簡(jiǎn)單的Pointer是不夠用了。

這種情況下,我們就需要使用Memory。

Memory是一種特殊的Pointer, 它保存了分配出來(lái)的空間大小。

我們來(lái)看一下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個(gè)數(shù)據(jù),我們接下來(lái)一一進(jìn)行介紹。

首先是最為重要的size,size表示的是Memory中內(nèi)存空間的大小,我們來(lái)看下Memory的構(gòu)造函數(shù)

    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類(lèi)型的數(shù)據(jù)需要傳入一個(gè)size參數(shù),表示Memory占用的空間大小。當(dāng)然,這個(gè)size必須要大于0.

然后調(diào)用native方法的malloc方法來(lái)分配一個(gè)內(nèi)存空間,返回的peer保存的是內(nèi)存空間的開(kāi)始地址。如果peer==0,表示分配失敗。

如果分配成功,則將當(dāng)前Memory保存到LinkedReference中,用來(lái)跟蹤當(dāng)前的位置。

我們可以看到Memory中有兩個(gè)LinkedReference,一個(gè)是HEAD,一個(gè)是reference。

LinkedReference本身是一個(gè)WeakReference,weekReference引用的對(duì)象只要垃圾回收?qǐng)?zhí)行,就會(huì)被回收,而不管是否內(nèi)存不足。

private static class LinkedReference extends WeakReference<Memory>

我們看一下LinkedReference的構(gòu)造函數(shù):

private LinkedReference(Memory referent) {
            super(referent, QUEUE);
        }

這個(gè)QUEUE是ReferenceQueue,表示的是GC待回收的對(duì)象列表。

我們看到Memory的構(gòu)造函數(shù)除了設(shè)置size之外,還調(diào)用了:

reference = LinkedReference.track(this);

仔細(xì)看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;
        }

這個(gè)方法的意思是首先從QUEUE中拿出那些準(zhǔn)備被垃圾回收的Memory對(duì)象,然后將其從LinkedReference中unlink。 最后將新創(chuàng)建的對(duì)象加入到LinkedReference中。

因?yàn)镸emory中的QUEUE和HEAD都是類(lèi)變量,所以這個(gè)LinkedReference保存的是JVM中所有的Memory對(duì)象。

最后Memory中也提供了對(duì)應(yīng)的read和write方法,但是Memory中的方法和Pointer不同,Memory中的方法多了一個(gè)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);
    }

為什么會(huì)有boundsCheck呢?這是因?yàn)镸emory和Pointer不同,Memory中有一個(gè)size的屬性,用來(lái)存儲(chǔ)分配的內(nèi)存大小。使用boundsCheck就是來(lái)判斷訪問(wèn)的地址是否出界,用來(lái)保證程序的安全。

感謝各位的閱讀,以上就是“JNA中的Memory和Pointer怎么使用”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)JNA中的Memory和Pointer怎么使用這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI