문제

현재 Cuda 기능을 사용하는 Java 신청을 만들려고 노력하고 있습니다. Cuda와 Java의 연결은 잘 작동하지만 또 다른 문제가 있고 그것에 대한 내 생각이 올바른지 물어보고 싶었습니다.

Java에서 기본 기능을 호출하면 일부 데이터를 전달하고 기능은 무언가를 계산하고 결과를 반환합니다. 첫 번째 함수가 JNI로 전달할 수있는이 결과에 대한 참조 (포인터)를 반환하고 결과와 함께 추가 계산을하는 다른 기능을 호출 할 수 있습니까?

저의 아이디어는 GPU 메모리에 데이터를 남겨두고 다른 기능이 사용할 수 있도록 데이터를 GPU로 가져 와서 GPU로 복사하여 오버 헤드를 줄이는 것이 었습니다.

시간을 시도한 후에는 응용 프로그램이 종료 된 후 (이 경우 C- 기능이 종료 될 때) 포인터가 삭제되기 때문에 이것은 나 자신을 위해 생각하지 않아야한다고 생각했습니다. 이 올바른지? 아니면 솔루션을보기 위해 C에서 나쁘게 나가는가?

편집 : 글쎄, 질문을 약간 확장하려면 (또는 더 명확하게 만들려면) : JNI 기본 함수에 의해 메모리가 할당되어 있습니까? 아니면 JNI 애플리케이션이 종료 될 때까지 또는 수동으로 자유롭게 해방 될 때까지 여전히 액세스 할 수 있습니까?

입력 해 주셔서 감사합니다 :)

도움이 되었습니까?

해결책

다음 접근 방식을 사용했습니다.

JNI 코드에서 필요한 객체에 대한 참조를 보유하는 구조물을 만듭니다. 이 구조물을 처음 만들 때, 포인터를 Java로 반환합니다. long. 그런 다음 Java에서 당신은 이것으로 모든 방법을 호출합니다. long 매개 변수로서 C에서 구조물에 대한 포인터로 시전합니다.

구조는 힙에 있으므로 다른 JNI 호출 사이에 지워지지 않습니다.

편집 : 긴 ptr =를 사용할 수 있다고 생각하지 않습니다. (long)&address; 주소는 정적 변수이므로. Gunslinger47이 제안한 방식으로 사용하십시오. 즉, 새로운 클래스 또는 구조물 (새 또는 malloc 사용)의 새로운 인스턴스를 만들고 포인터를 통과하십시오.

다른 팁

C ++에서는 스택, malloc/free, new/delete 또는 기타 사용자 정의 구현과 같은 메커니즘을 할당/무료 메모리를 사용할 수 있습니다. 유일한 요구 사항은 하나의 메커니즘으로 메모리 블록을 할당하면 동일한 메커니즘으로 자유롭게해야하므로 전화를 걸 수 없다는 것입니다. free 스택 변수에서 호출 할 수 없습니다 delete ~에 malloc에드 메모리.

JNI는 JVM 메모리를 할당/해제하기위한 자체 메커니즘을 가지고 있습니다.

  • NewObject/deletelocalref
  • Newglobalref/deleteglobalref
  • Newweakglobalref/deleteweakglobalref

이것들은 동일한 규칙을 따릅니다. 유일한 캐치는 로컬 심판을 명시 적으로 "en en masse"로 삭제할 수 있다는 것입니다. PopLocalFrame, 기본 메소드가 종료 될 때, 또는 암시 적으로.

JNI는 메모리를 어떻게 할당했는지 알지 못하므로 기능이 종료 될 때는 무료로 메모리를 할 수 없습니다. 여전히 C ++를 작성하기 때문에 스택 변수가 분명히 파괴되지만 GPU 메모리는 유효합니다.

그런 다음 유일한 문제는 후속 호출에서 메모리에 액세스하는 방법입니다. 그런 다음 Gunslinger47의 제안을 사용할 수 있습니다.

JNIEXPORT jlong JNICALL Java_MyJavaClass_Function1() {
    MyClass* pObject = new MyClass(...);
    return (long)pObject;
}

JNIEXPORT void JNICALL Java_MyJavaClass_Function2(jlong lp) {
    MyClass* pObject = (MyClass*)lp;
    ...
}

Java는 포인터로 무엇을 해야할지 알지 못하지만 기본 기능의 리턴 값에서 포인터를 저장 한 다음 다른 기본 기능으로 나눠 줄 수 있어야합니다. C 포인터는 코어에서 숫자 값에 지나지 않습니다.

또 다른 컨디셔너는 JNI 호출 사이에 그래픽 메모리가 지적되는지 여부와 작업 어라운드가 있을지 여부를 알려야합니다.

이 질문이 이미 공식적으로 답변되었음을 알고 있지만 솔루션을 추가하고 싶습니다. 포인터를 전달하는 대신 포인터를 Java 어레이 (색인 0)에 넣고 JNI로 전달하십시오. JNI 코드는 사용하여 배열 요소를 가져 와서 설정할 수 있습니다. GetIntArrayRegion/SetIntArrayRegion.

내 코드에서는 파일 디스크립터 (열린 소켓)를 관리하려면 기본 레이어가 필요합니다. Java 클래스는 a int[1] 배열 및 기본 기능으로 전달합니다. 기본 함수는 무엇이든 수행 할 수 있으며 (GET/SET) 결과를 배열에 다시 넣을 수 있습니다.

기본 기능 내부의 메모리를 동적으로 (힙에) 할당하는 경우 삭제되지 않습니다. 다시 말해, 포인터, 정적 VAR 등을 사용하여 다른 호출 사이의 상태를 기본 함수로 유지할 수 있습니다.

다른 방식으로 생각하십시오 : 다른 C ++ 프로그램에서 불리는 기능 호출을 안전하게 유지할 수 있습니까? 여기에도 같은 것이 적용됩니다. 함수가 종료되면 해당 함수 호출에 대한 스택의 모든 것이 파괴됩니다. 그러나 명시 적으로 삭제하지 않으면 힙의 모든 것이 유지됩니다.

짧은 답변 : 호출 함수로 돌아 오는 결과를 처리하지 않는 한 나중에 재 입력에 유효합니다. 완료되면 정리하십시오.

@denis-tulskiy의 수락 된 답변은 의미가 있지만, 나는 개인적으로 제안을 따랐습니다. 여기.

따라서 의사 포인터 유형을 사용하는 대신 jlong (또는 jint 32bits 아치에 공간을 절약하려면 대신 사용하십시오. ByteBuffer. 예를 들어:

MyNativeStruct* data; // Initialized elsewhere.
jobject bb = (*env)->NewDirectByteBuffer(env, (void*) data, sizeof(MyNativeStruct));

나중에 재사용 할 수 있습니다.

jobject bb; // Initialized elsewhere.
MyNativeStruct* data = (MyNativeStruct*) (*env)->GetDirectBufferAddress(env, bb);

매우 간단한 경우이 솔루션은 사용하기가 매우 쉽습니다. 당신이 가지고 있다고 가정합니다.

struct {
  int exampleInt;
  short exampleShort;
} MyNativeStruct;

Java 측에서는 단순히 다음과 같이해야합니다.

public int getExampleInt() {
  return bb.getInt(0);
}

public short getExampleShort() {
  return bb.getShort(4);
}

글쓰기에서 벗어나게됩니다 많이 보일러 플레이트 코드! 그러나 설명 된대로 바이트 주문에주의를 기울여야합니다. 여기.

이 작업을 수행하는 것이 가장 좋습니다.

객체를 만들면 32/64 비트 서명 된 정수 인 (UINTPTR_T)에 입력하십시오.

return (uintptr_t) malloc(50);

void * f = (uintptr_t) jlong;

이것이 유일한 올바른 방법입니다.

안전하지 않은 정신 검사는 다음과 같습니다.

inline jlong addr_to_java(void* p) {
  assert(p == (void*)(uintptr_t)p, "must not be odd high bits");
  return (uintptr_t)p;
}

UNSAFE_ENTRY(jlong, Unsafe_AllocateMemory(JNIEnv *env, jobject unsafe, jlong size))
  UnsafeWrapper("Unsafe_AllocateMemory");
  size_t sz = (size_t)size;
  if (sz != (julong)size || size < 0) {
    THROW_0(vmSymbols::java_lang_IllegalArgumentException());
  }
  if (sz == 0) {
    return 0;
  }
  sz = round_to(sz, HeapWordSize);
  void* x = os::malloc(sz, mtInternal);
  if (x == NULL) {
    THROW_0(vmSymbols::java_lang_OutOfMemoryError());
  }
  //Copy::fill_to_words((HeapWord*)x, sz / HeapWordSize);
  return addr_to_java(x);
UNSAFE_END
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top