You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java通过JNA调用Delphi DLL多次后出现无效内存访问错误排查

问题分析:Java通过JNA调用Delphi DLL出现"Invalid memory access"错误

Java通过JNA调用自行开发的Delphi DLL时,前几次调用正常,但多次调用后抛出Invalid memory access错误。仅在将结果转为PAnsiChar返回给Java时触发该问题,直接将结果写入文件则无异常。


相关代码信息

Java接口签名

public interface DLL extends Library {

    DLL CCAWDll = Native.load("invoke", DLL.class);

    String invoke(String fileName, float a, float b, float c, float d,
                 float e, float f, float g, float h, float i,
                 float j, String k);

}

Delphi函数签名

function invoke(filename: PAnsiChar; a, b, c, d, e, f, g, h, i, j: single; k: PAnsiChar): PAnsiChar; stdcall;

错误栈信息

===================================9th time, call DLL===================================
===================================10th time, call DLLL===================================
2023-03-10 10:25:56.417 ERROR 12592 --- [-nio-94-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : > Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.Error: Invalid memory access] with root cause

java.lang.Error: Invalid memory access
  at com.sun.jna.Native.invokePointer(Native Method) ~[jna-5.5.0.jar:5.5.0 (b0)]
  at com.sun.jna.Function.invokePointer(Function.java:497) ~[jna-5.5.0.jar:5.5.0 (b0)]
  at com.sun.jna.Function.invokeString(Function.java:660) ~[jna-5.5.0.jar:5.5.0 (b0)]
  at com.sun.jna.Function.invoke(Function.java:434) ~[jna-5.5.0.jar:5.5.0 (b0)]
  at com.sun.jna.Function.invoke(Function.java:361) ~[jna-5.5.0.jar:5.5.0 (b0)]
  at com.sun.jna.Library$Handler.invoke(Library.java:265) ~[jna-5.5.0.jar:5.5.0 (b0)]
  at com.sun.proxy.$Proxy98.invoke(Unknown Source) ~[na:na]
  at com.xxx.xxx.dll.impl.DllImpl.invoke(DllImpl.java:40) ~[classes/:na]
  at com.xxx.xxx.dll.impl.DllImpl$$FastClassBySpringCGLIB$$92dce636.invoke(<generated>) ~[classes/:na]
  at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.12.RELEASE.jar:5.1.12.RELEASE]
  at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:750) ~[spring-aop-5.1.12.RELEASE.jar:5.1.12.RELEASE]
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.1.12.RELEASE.jar:5.1.12.RELEASE]
  at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:120) ~[spring-context-5.1.12.RELEASE.jar:5.1.12.RELEASE]
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.12.RELEASE.jar:5.1.12.RELEASE]
  at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689) ~[spring-aop-5.1.12.RELEASE.jar:5.1.12.RELEASE]
  at com.xxx.xxx.dll.impl.DllImpl$$EnhancerBySpringCGLIB$$c67e343.invoke(<generated>) ~[classes/:na]
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_341]
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_341]
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_341]
  at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_341]

Java调用代码

public  class DllImpl extends DllManage implements DllProvider {

    public static AtomicInteger count = new AtomicInteger(0);
    @Override
    public synchronized ResponseEntity<String> invoke(String fileName, float a, float b,
                                                      float c, float d, float e, float f, float g, float h, float i, float j, String k) {
        System.setProperty("jna.encoding", "GBK");
        count.getAndIncrement();
        String result = null;
        System.out.println("==================================="+count+"th time, call DLL===================================");
        try {
            result = DLL.CCAWDll.invoke(fileName,
                    a,b,c,d,e,f,g,h,i,j,
                    k);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        System.gc();
        return new ResponseEntity<>(result, HttpStatus.OK);

    }
}

Delphi核心逻辑

QueryPerformanceCounter(t2); // Get end count value
r1 := (t2 - t1) / c1; // Get the timing time in seconds (s)
r2 := (t2 - t1) / c1 * 1000; // Get the timing time in milliseconds (ms)
r3 := (t2 - t1) / c1 * 1000000; // Get the timing time in microseconds
WritelnTxt('fileName:' + filename);
WritelnTxt('Time of calling CCAWDll:' + FloatToStr(r2));
//TJsonSerializer class, more efficient and faster
serial := TJsonSerializer.Create;
S := serial.Serialize<INSOLUTION>(returnDetail); // [{"name": "Zhang Zhang", "age": 1}, {"name": "Wang Wang", "age": 2}]
QueryPerformanceCounter(t3); // Get end count value
r4 := (t3 - t2) / c1 * 1000; // Get timing time
WritelnTxt('Generate json time:' + FloatToStr(r4));
//write file
WritelnTxtFile(S);
//return 
GetMem(PStr, Length(S) + 1); // This 1 is used to store the 0 string terminator
StrPCopy(PStr, S);
Result := PAnsiChar(PStr);

问题结论

问题根源是DLL内部内存管理缺陷,参数类型匹配无问题:

  1. 参数类型验证:Java的float对应Delphi的single,String对应PAnsiChar,调用约定为stdcall,参数数量、顺序完全匹配,不存在类型不匹配问题。
  2. 内存泄露引发非法访问:Delphi通过GetMem分配内存并返回给Java,但没有释放机制。每次调用都会占用新内存,多次调用后内存耗尽,后续GetMem可能分配到无效区域,或JNA读取时访问已被系统回收的内存,触发Invalid memory access。直接写入文件无需分配返回内存,因此无异常。
  3. 佐证:固定第10次调用出错符合内存逐步耗尽的特征;System.gc()无法解决,因为Java无法管理Delphi分配的本地内存。

解决方案

方案一:DLL提供内存释放函数

Delphi新增释放函数:

procedure FreeMemStr(P: PAnsiChar); stdcall;
begin
  if P <> nil then FreeMem(P);
end;

Java接口新增对应方法并调用:

void FreeMemStr(String str);

// 调用后释放内存
try {
    result = DLL.CCAWDll.invoke(...);
    // 处理结果
} finally {
    if (result != null) {
        DLL.CCAWDll.FreeMemStr(result);
    }
}

方案二:Java分配内存传入DLL

由Java提前分配足够的内存缓冲区,DLL直接写入该缓冲区,避免跨边界内存管理问题。

方案三:使用共享内存管理器(不推荐)

使用Delphi的SharedMem单元,让内存分配和释放使用共享内存管理器,但兼容性较差,仅适合特定场景。

内容的提问来源于stack exchange,提问作者JnoZhen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 19:02:04