千家信息网

JNA中的Memory和Pointer怎么使用

发表于:2025-02-21 作者:千家信息网编辑
千家信息网最后更新 2025年02月21日,这篇文章主要讲解了"JNA中的Memory和Pointer怎么使用",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"JNA中的Memory和Pointer
千家信息网最后更新 2025年02月21日JNA中的Memory和Pointer怎么使用

这篇文章主要讲解了"JNA中的Memory和Pointer怎么使用",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"JNA中的Memory和Pointer怎么使用"吧!

简介

我们知道在native的代码中有很多指针,这些指针在JNA中被映射成为Pointer。

Pointer

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:Opaque

在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);        }

Memory

Pointer是基本的指针映射,如果对于通过使用native的malloc方法分配的内存空间而言,除了Pointer指针的开始位置之外,我们还需要知道分配的空间大小。所以一个简单的Pointer是不够用了。

这种情况下,我们就需要使用Memory。

Memory是一种特殊的Pointer, 它保存了分配出来的空间大小。

我们来看一下Memory的定义和它里面包含的属性:

public class Memory extends Pointer {...    private static ReferenceQueue QUEUE = new ReferenceQueue();    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

我们看一下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就是来判断访问的地址是否出界,用来保证程序的安全。

感谢各位的阅读,以上就是"JNA中的Memory和Pointer怎么使用"的内容了,经过本文的学习后,相信大家对JNA中的Memory和Pointer怎么使用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

方法 对象 内存 指针 空间 分配 地址 大小 数据 函数 就是 实际 实际上 属性 类型 学习 不同 特殊 接下来 两个 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 防诈骗网络安全内容班会形式设计 服务器安全管理规定 饿了吗 网络技术团队 思科网络技术学院显示审核中 房地产成本数据库如何建立 网络安全火眼金睛游戏 大连华盛恒辉软件开发公司 数据库战略研讨会 宁夏 数据库安全 爱数 杭州最好的外贸数据库系统排名 删除数据库日志文件的语句 从云服务器同步设置 美国服务器低价 新炬网络最大数据库 江苏服务器供应商虚拟主机 金蝶商贸标准版数据库怎么装 众人互联网科技有限公司建站 网络安全大咖组团 lte模组平台软件开发 广西番摊软件开发 如何通过客户编号找到数据库价格 杨浦区信息化软件开发服务报价表 数据库加快数据查询速度 软件开发版本号作用 手机 ftp服务器 网络安全ppt背景免费 数据库数据怎么压缩包 在线考试系统数据库的连接 大学法制文化培训基地软件开发 电竞酒店服务器延迟很高
0