Java 使用JNA调用本地动态库报错:EXCEPTION_ACCESS_VIOLATION (0xc0000005)

在Java项目中使用JNA调用C++动态库dll时遇到程序崩溃,错误代码0xC0000374指示内存问题。通过分析发现可能是由于内存重复释放导致。检查代码后发现在Memory对象关闭时,释放内存的操作执行了两次,修正此问题后通过设置指针为null防止二次释放,解决了程序异常退出的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天在做项目的时候,因为需要调用C++同事的本地动态库XXXX.dll 文件,所以引用了jna.

jna介绍

JNA(Java Native Access )提供一组Java工具类用于在运行期间动态访问系统本地库(native library:如Window的dll)而不需要编写任何Native/JNI代码。开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射。

实际上就是不需要自己写额外的代码就能正常访问本地c++ 代码方法的Java封装。

如何调用,可以参考网上的教程或者案例,在此不做讲述。

问题再现

我是用的是封装过的jar 包,用来调用dll 文件中的动态方法。在创建实例对象的时候,都没有问题。但是在程序运行一段时间后,系统直接退出,并且显示:
Process finished with exit code -1073740940 (0xC0000374)

这句话的意思实际上是:垃圾回收器在尝试回收内存时遇到了异常,从而导致程序停止运行。

但是具体什么问题导致的停止,却没有显示。内存溢出的可能性十分大。

于是乎,我查看jconsole , 发现内存波动很正常,好像并没有什么大问题。

但是当我手动点击GC的时候,系统突然崩掉。并且打印一堆JVM错误信息:
 

A fatal error has been detected by the Java Runtime Environment:

EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffd8c6b5bb6, pid=13076, tid=0x0000000000002a78

 JRE version: Java(TM) SE Runtime Environment (8.0_331-b09) (build 1.8.0_331-b09)
 Java VM: Java HotSpot(TM) 64-Bit Server VM (25.331-b09 mixed mode windows-amd64 compressed oops)
 Problematic frame:
 C  [ntdll.dll+0x25bb6]

注意,这里报错显示EXCEPTION_ACCESS_VIOLATION,这个错误是访问异常导致。

具体执行文件是本地的  ntdll.dll 文件,该文件主要是和堆有关。

于是乎 ,我点击进去查看 jar包的调用形式:
 

public class Image implements AutoCloseable {
   private Pointer ptr = new Memory(1048576L);

    public Image(String path) throws UnsupportedFormatException {
        try {
            port.load(this.ptr);
            boolean support = port.can_be_file(this.ptr, path);
            if (!support) {
                this.close();
                throw new UnsupportedFormatException("不支持的文件格式");
            } else {
                  ///...可以用
            }
        } catch (Exception var3) {
            this.close();
            throw var3;
        }
    }
}

貌似new 构造函数的时候并没有啥问提,一开始以为是c++ 那里的问题,可回头想,可能这边定义有误,要不然怎么是过了一会儿就死掉了?

于是乎继续看下去:

// 释放内存
  public void close() {
    long peer =    Pointer.nativeValue(ptr);
    Native.free(peer);
    Pointer.nativeValue(ptr,0L);
  }

这个实际上也没有问题。但是!! JVM报错中有一个很重要的信息:
 

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  com.sun.jna.Native.free(J)V+0
j  com.sun.jna.Memory.free(J)V+7
j  com.sun.jna.Memory$MemoryDisposer.run()V+4
j  com.sun.jna.internal.Cleaner$CleanerRef.clean()V+15
j  com.sun.jna.internal.Cleaner$1.run()V+22
v  ~StubRoutines::call_stub

虚拟机在处理的时候,调用了Memory.free() 方法了,free 下面又调用了Native.free 。

这个时候,结合上面的代码突然发现,这个释放好像是走了两边?? 于是乎 我把指针 ptr 置为null:

this.ptr = null;

再次运行项目,就正常了。因为置为null 所以JVM就知道这个变量实际是一个可回收的变量。

所以,这个错误很有可能是JVM在进行清理的时候,出现二次释放的问题导致的!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值