2016-06-07 3 views
0

JNA를 사용하여 기본 lib에 액세스하고 있습니다. 이것은 JNA에서 처음으로 작업 한 것이므로 c/C++에 대한 경험이 없습니다. 응용 프로그램을 작동시킬 수 있었고 올바른 결과가 반환되고 System.out.println()을 사용하여 표시되었습니다. 이것은 내 코드의 마지막 줄입니다. 값이 콘솔에 표시되고 Java 충돌이 발생합니다 (예 : 대화 상자 Java Platform SE binary has stopped working이 닫히거나 디버그 할 수있는 옵션과 함께 표시됩니다.Java JNA : 응용 프로그램 완료 후 JRE가 충돌 함

후 콘솔이 보여줍니다

Java Result: -1073741819

내 코드 : C에서 함수의

public static void main(String[] args) { 

    FloatByReference result = new FloatByReference(); 
    //EDIT: changed to NativeLongByReference as per suggested answer 
    NativeLongByReference numContrib = new NativeLongByReference();  
    // This is a struct that needs to be passed by reference 
    MyDll.PContribution.ByReference contrib = new MyDll.PContribution.ByReference();   
    NativeLong err = MyDll.INSTANCE.calcResult("myValue", result, numContrib, contrib); 
    // I only care about result and not the other out-parameters 
    System.out.println(result.getValue()); 
    //crash here 
} 

(고화질)는 :

typedef long (CALCRESULT)(const char*, float*, long*, HANDLE*);

뭐가 잘못 이죠? 응용 프로그램이 종료되기 전에 정리를 수행해야합니까?

편집 :

루프에서 메소드 호출을 실행할 수 있으며 작동합니다. 종료 될 때만 추락합니다.

EDIT2 :

MyDll 여기 코멘트 코드 당으로 다음 struct

public interface MyDll extends Library { 

    public static class PContribution extends Structure { 
     public static class ByReference extends PContribution implements Structure.ByReference { 

       public byte[] Class = new byte[10]; 
       public byte[] Type = new byte[6]; 
       public byte[] Description = new byte[40]; 
       public byte[] Comment = new byte[10]; 
       public float Value; 
     } 
      protected List<String> getFieldOrder() { 
        return Arrays.asList(new String[] { "Class", "Type", "Description", "Comment", "Value" }); 
       } 
} 

    MyDll INSTANCE = (MyDll) Native.loadLibrary("MyDll", MyDll.class); 

    NativeLong calcResult(String smi, FloatByReference result, NativeLongByReference numContrb, PContribution contrib); 
} 

정의 :

typedef struct { 
    char Class[10]; 
    char Type[6]; 
    char Description[40]; 
    char Comment[10]; 
    float Value; 
} PContribution; 

편집 3 :

젠장. 사용 가능한 문서가 dll의 이전 버전 용이라는 것을 알아 냈습니다. 이전 dll을 사용하면 모든 것이 작동합니다. 이제 공급자로부터 새 버전의 문서를 받아야합니다.

EDIT 4 :

그것은 오래된 DLL로 작동하지만 응용 프로그램은 지속적으로 65533 반복 (전화) 후 충돌합니다. 각 호출은 정확히 동일한 매개 변수를 사용합니다.

java.lang.Error: Invalid memory access 

at com.sun.jna.Native.invokeInt(Native Method) 
at com.sun.jna.Function.invoke(Function.java:390) 
at com.sun.jna.Function.invoke(Function.java:323) 
at com.sun.jna.Library$Handler.invoke(Library.java:236) 
at com.sun.proxy.$Proxy0.calcLogP(Unknown Source) 

실습의 요점은 수천 번의 호출을 신속하게 수행 할 수 있다는 것입니다.

+0

'MyDll'에 대한 클래스 정의도 게시하십시오. 'calcResult()'에 대한 선언은 여기에 관련있다. [최소한의 완전하고 검증 가능한 예제를 만드는 방법] (http://stackoverflow.com/help/mcve) –

+0

편집을 참조하십시오. 나는 dll을 공유 할 수 없기 때문에 실행 가능한 예제를 만들 수 없습니다. –

+0

나는 dll에 문제가있는 것 같았다. 가능한 원인에 대해 좀 더 자세히 설명하도록 내 답변을 업데이트하십시오. –

답변

1

Java 결과는 오류 메시지입니다. -1073741819는 STATUS_ACCESS_VIOLATION의 코드 인 0xc0000005입니다. 권한이없는 메모리에 액세스하고 있습니다.

응용 프로그램이 닫힐 때 발생한다는 사실은 프로그램이 종료 될 때 발생하며 가비지 수집이 트리거 될 때 발생할 수있는 개체 종료와 관련되어 있음을 나타냅니다. Java/JNA가 C가 할당하지 않은 메모리를 해제하려고 시도 할 가능성이 있습니다.당신은 당신이 조사해야 오류 이런 종류의 얻을 때

: JNA에 C에서

  • 유형 매핑을 (특히 객체 크기)
  • 메모리 할당 불일치 자바 (면이 메모리를 할당한다) C 대 당신의 API에 의해 C 측에 할당
  • 해제 리소스/메모리 (핸들, 참조, 포트 등)

타입 매핑

코드와 c 함수 정의를 비교하면 두 가지 불일치가 나타납니다.

  • CALCRESULT 기능이 있는지 여부 C.에 long에 대한 포인터를 가진 32 비트 또는 자바의 long 항상 64 비트 동안 operating system dependent 64 비트 길이. 기본 long 값을 JNA의 NativeLong 유형에 매핑해야합니다. 이 경우 크래시가 발생하지 않을 수도 있지만 값이 배열 또는 구조 안에있을 때이 차이를 알면 바이트 오프셋을 버리게되므로 매우 중요합니다. 기본 long에 대한 포인터로, 당신의 변수 numContrib 그러므로 유형 NativeLongByReference

  • CALCRESULT 기능은 C에서 HANDLE 유형에 대한 포인터를 가지고이어야합니다,하지만 당신은 (참조) 구조를 전달합니다. 여기에 몇 가지 메모가 있습니다 :

    • ByReference를 사용해야하는 이유가 확실하지 않습니다. 이와 같이 인수를 구조체로 전달하면 JNA는이를 포인터로 변환하고 메모리를 할당하고 해제하며 구조체에 네이티브 메모리를 자동으로 읽습니다. 그래서 일반적으로 참조로 구조체를 전달하지 않을 것입니다. (개인적으로, ByReference 구조체를 피하고 바로 포인터를 사용하여 새로운 구조체를 만드는 Pointer을 직접 조작하는 것이 좋을 것입니다.
    • C 메서드는 포인터에 특정 포인터를 지정합니다. Windows 유형은 HANDLE입니다. A Handle은 다른 시스템 리소스에 액세스 할 수있는 내부적으로 유지 관리되는 테이블에 대한 참조입니다. 핸들은 사용을 마쳤거나 해당 리소스를 묶어야합니다. JNA는 HANDLE 유형을 모델링합니다. 이 경우에는 포인터가 있으므로 적절한 유형은 HANDLEByReference 일 것입니다.

메모리 할당 불일치 당신이 API는 당신에게 HANDLE 유형에 대한 포인터를 제공하는 구조를 사용하는 이유가 불분명

(JNA HANDLEByReference). Java는 구조의 new 인스턴스 (PContribution)를 정의 할 때 필요한 메모리를 할당하고 JNA는 해당 Java 메모리를 로컬 메모리에 매핑합니다. 그러나 C 함수는 정의한 구조보다 적은 메모리를 차지하는 HANDLE 형식에 대한 포인터를 제공합니다. Java가 구조체 메모리를 해제하고 C 측에서 동일한 메모리를 해제하려고 할 때 C가 할당 된 것보다 더 많은 메모리 (구조체)를 릴리스 할 것이기 때문에 문제가 발생합니다. 핸들).이 핸들에서 가져온 구조에 대한 API의 명확한 문서가 없으면 이에 대한 자세한 답변을 드릴 수 없습니다.

해제 자원

API가이 참여하는 메모리보다 가능성이 다른 자원 년대 HANDLE 유형을 사용하고, 당신이 그 참조를 해제 할 책임이 있기 때문에. CloseHandle() 함수를 참조하십시오. 이 함수로 핸들을 직접 닫아야하는지 아니면 API가 내부적으로 CloseHandle() internall을 구현하는 자체 메서드 중 하나를 사용하여 API를 닫을 지 여부는 API에 명확하게 문서화되어야합니다 (이 경우 CALCRESULT 함수). 검사 할 API가 없으면 더 이상 도움을 줄 수는 없지만 코드에서 작성한 구조가 명시 적으로 해제되거나 해제되어야하는지 여부를 확인하기 위해 설명서를주의 깊게 읽습니다.

+0

32 비트 윈도우에 있습니다. 나는 변화를 만들었지 만 같은 문제가 발생합니다. 사실 두 경우 모두'numContrib.getValue()'를 호출 할 수 있으며 값이 좋으며 응용 프로그램을 호출 할 때 응용 프로그램이 충돌하지 않습니다. 어쩌면이 문제는'struct'와 관련이 있습니다. 내 편집을 참조하십시오. –

+0

답변을 업데이트했습니다. 구조물에 대한 메모리가 언제/어디서 할당되는지에 세심한주의를 기울이십시오. 왜 ByReference인가? –

+0

네이티브 long은 win32 및 win64 (항상 32 비트)에서 크기가 동일합니다. – technomage