문제

게 말씀으로 시작하는 대한 이해의 방법 JNA 및 Java 직접 기본 메모리 할당 내에서 최고의,그래서 나는 설명하기 위해 노력하고 내의 이해는 무슨 일이 일어나고 있는지.모든 수정 사항 외에도 응답이 될 것이 큰...

나는 응용 프로그램을 실행하는 호텔 Java 와 C 기본 코드를 사용하여 JNA 고 실행에 걸쳐 재현 가능한 문제와 자바 쓰레기 수집가 실패하는 무료 참조하여 직접 기본 메모리 할당,그 결과 C 힙 메모리가 부족합니다.

나는 긍정적인 내 C 응용 프로그램의 원인이 아닌지 확인할 수 있습니다 할당 문제,나는 통과하는 java.nio.ByteBuffer 내 C 코드,수정 버퍼,그리고 다음에 액세스하는 결과 내 Java 기능입니다.단일 malloc 와 해당하는 단일 free 안 각 함수 호출,그 후에는 반복적으로 실행되는 코드에서 Java malloc 는 결국 실패입니다.

여기에는 다소 평범의 설정 코드는 전시 문제-- 현실적으로 나가려고 할당 약 16-32MB C 힙 동안 함수 호출에.

내 Java 코드는 다음과 같습니다.

public class MyClass{
    public void myfunction(){
        ByteBuffer foo = ByteBuffer.allocateDirect(1000000);
        MyDirectAccessLib.someOp(foo, 1000000);
        System.out.println(foo.get(0));
    }
}

public MyDirectAccessLib{
    static {
        Native.register("libsomelibrary");
    }
    public static native void someOp(ByteBuffer buf, int size);
}

내 C 코드 같은 수 있습니다:

#include <stdio.h>
#include <stdlib.h>
void someOp(unsigned char* buf, int size){
    unsigned char *foo;
    foo = malloc(1000000);
    if(!foo){
        fprintf(stderr, "Failed to malloc 1000000 bytes of memory\n");
        return;
    }
    free(foo);

    buf[0] = 100;
}

문제는 이 함수를 호출한 후에 반복적으로 Java 힙소(안정적 성장을 천천히)지만,C 기능이 결국 할당할 수 없습니다.더 메모리입니다.높은 수준에서 내가 이것을 믿기 때문에 자바 메모리 할당 C 힙지만 청소의 bytebuffer 는 점에서 이는 메모리기 때문에 자바의 bytebuffer 개체는 비교적 작은 있습니다.

지금까지 발견했을 실행하 GC 에서 수동으로 제 기능을 제공할 것이 필수 정리,그러나 이것은 모두 같은 가난한 아이디어와 가난한 솔루션입니다.

어떻게 관리할 수 있습니는 이 문제를 더 잘 그래의 bytebuffer 공간을 적절하게 해제하고 내 C 힙 공간이 통제되는가?

는 문제에 대한 이해 잘못된(뭔가가 나는 실행하는 부적절하게)?

편집:조정된 버퍼 크기를 더 사려깊은 나의 실제 응용 프로그램,내가 할당 이미지에 대한 약 3000x2000...

도움이 되었습니까?

해결책

내가 생각하는 진단을 제대로:당신은 부족하지 않 Java 힙,그래서 JVM 지 않는 쓰레기를 수집하고,매핑된 버퍼지 않을 해제됩니다.사실 당신은하지 않는 문제가 실행하는 경우 GC 수동으로는 것을 확인합니다.할 수 있도록 설정에 대한 자세한 컬렉션 로깅으로 보조 확인합니다.

그래서 당신은 무엇을 할 수 있습니까?라,첫 번째 일을 하려고 유지하는 것입 초기 JVM heap 크기의 작은,사용-Xms 명령줄 인수입니다.이 문제를 일으킬 수 있는 경우,귀하의 프로그램을 지속적으로 할당하는 소량 메모리에서 Java 힙,그것이 실행됩니다 GC 더 자주.

도를 사용하여 pmap 구(또는 그와 동등한 윈도우에서)을 검사하여 가상 메모리 맵.그것은 가능한 한 당신이 조각화하는 방법 C 힙 할당하여,해당 변수 크기의 버퍼가 있습니다.는 경우,그 다음 당신은 모든 큰 가상으로,지도 틈 사이에"곧"니다.과 해결책이 있을 할당 일정한 크기의 블록보다 큰 당신이 필요합니다.

다른 팁

당신은 실제로 직면하는 에서 알려진 버그 Java VM.최선의 해결 방법에 나와 버그 보고서:

  • "-XX:MaxDirectMemorySize=옵션을 사용할 수 있습의 양을 제한 직접적인 메모리 사용됩니다.하려는 시도를 할당 직접 메모리키는 이러한 제한을 초과 발생 가득 GC 도록 자극을 참조 처리 및 출시 참조되지 않은 버퍼입니다."

가능한 다른 해결 방법을 포함한다:

  • 삽입이 가끔은 명시적 시스템입니다.gc()호출을 지키는 것에 직접 버퍼가 매립지.
  • 의 크기를 줄이 젊은 세대를 강제로 더 자주 GCs.
  • 명시적으로 수영장에 직접 버퍼는 애플리케이션 레벨에서.

당신이 정말로 원하는 경우에 의존하는 직접적인 바이트 버퍼,다음이 풀링 애플리케이션 레벨에서.복잡도에 따라 응용 프로그램의할 수 있습니다 심지어는 단순히 캐시고 다시 사용하는 동일 버퍼(주의 여러 스레드)을 사용할 수 있습니다.

내가 심는 당신의 문제는 사용으로 인해 direct 바이트 버퍼입니다.그들은 할당될 수 있는 외부의 자바 힙.

는 경우에 당신을 호출하는 방법을 자주 할당하고 작은 버퍼의 각 시간,사용하지 않는 것이 좋에 맞게 직접 버퍼입니다.

을 분리하기 위해 문제,나는 스위치(Java)힙-할당된 버퍼(사용 allocate 방법 장소에서의 allocateDirect.는 경우에는 메모리 문제를 멀리,당신이 발견한 원인이다.다음 질문이 될 것인지 여부 direct 바이트 버퍼 어떤 이점 성능.하지 않을 경우(그리고 나는 생각하지 않는 것),다음은 걱정할 필요가 없을 청소하는 방법에 대한 제대로.

당신의 힙 메모리 GC 는 자동으로 실행됩.그러나 실행하는 경우 직접적인 메모리 GC 트리거되지 않습(에 태양의 JVM 이상)그리고 당신은 단지는 메모리 부족한 경우에도 GC 을 자유롭게 하는 것이 충분한 메모리입니다.내가 찾은 당신 트리거 GC 으로 이 상황입니다.

더 나은 솔루션이 될 수 있습니다 다시 사용을 동의 bytebuffer 그래서 당신은 필요하지 않 re-acllocate ByteBuffers.

을 무료로 직접 Bufferko [1] 메모리 사용할 수 있습니다 JNI.

기능 GetDirectBufferAddress(JNIEnv* env, jobject buf)[3]JNI6API 를 획득하는데 사용될 수있다 포인터를 메모리에 대한 Buffer 다음 표준 free(void *ptr) 명령에 대한 포인터 메모리.

보다는 코드 작성 등의 C 전화를 말하는 기능에서 Java 를 사용할 수 있습니다 JNAko Native.getDirectBufferPointer(Buffer)[6]

남은 것은 그 후 모든 대한 참조 Buffer 체입니다.Java 의 가비지 컬렉션은 그 다음을 무료 Buffer 인스턴스가 다른 어떤 참조되지 않 개체입니다.

참고는 직접적인 Buffer 지 않는 반드시 지도 1:1 을 할당된 메모리 영역.예를 들어 JNI API NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity)[7].이와 같이,당신은 단지 메모리의 Buffer's,누구의 메모리 할당 지역 당신이 알고 하나 하나의 기본 메모리입니다.

나도 알지 못할 수 있는 경우 무료로 직접 Buffer 에 의해 만들어 Java ByteBuffer.allocateDirect(int)[8] 에 대한 정확히 같은 이유로이다.수 JVM 또는 자바 플랫폼 구현 특정 정보를 사용 여부에 상관없이 수영장 또는 1:1 메모리 할당할 때 나눠 새로운 직접 Buffers.

여기에 다음과 같이 약간 수정된 조각에서 내 라이브러리에 대한 직접적인 ByteBuffer[9] 취급(사용 JNA Native[10]Pointer[11] 클래스):

/**
 * Allocate native memory and associate direct {@link ByteBuffer} with it.
 * 
 * @param bytes - How many bytes of memory to allocate for the buffer
 * @return The created {@link ByteBuffer}.
 */
public static ByteBuffer allocateByteBuffer(int bytes) {
        long lPtr = Native.malloc(bytes);
        if (lPtr == 0) throw new Error(
            "Failed to allocate direct byte buffer memory");
        return Native.getDirectByteBuffer(lPtr, bytes);
}

/**
 * Free native memory inside {@link Buffer}.
 * <p>
 * Use only buffers whose memory region you know to match one to one
 * with that of the underlying allocated memory region.
 * 
 * @param buffer - Buffer whose native memory is to be freed.
 * The class instance will remain. Don't use it anymore.
 */
public static void freeNativeBufferMemory(Buffer buffer) {
        buffer.clear();
        Pointer javaPointer = Native.getDirectBufferPointer(buffer);
        long lPtr = Pointer.nativeValue(javaPointer);
        Native.free(lPtr);
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top