[java] ByteBuffer.allocate () 대 ByteBuffer.allocateDirect ()

allocate()나에 allocateDirect(), 그 질문은.

몇 년 동안 나는 DirectByteBuffers가 OS 수준에서 직접 메모리 매핑 이기 때문에 s보다 get / put 호출을 더 빠르게 수행 할 것이라는 생각에 매달렸다 HeapByteBuffer. 나는 지금까지 상황에 관한 정확한 세부 사항을 찾는 데 정말로 관심이 없었습니다. 나는 두 가지 유형 중 어느 ByteBuffer것이 더 빠르며 어떤 조건에 있는지 알고 싶습니다 .



답변

그의 뛰어난 저서 인 Java NIO 에서 Ron Hitches는 귀하의 질문에 대한 좋은 답변이 될 수 있다고 생각한 것을 제공하는 것 같습니다.

운영 체제는 메모리 영역에서 I / O 작업을 수행합니다. 이러한 메모리 영역은 운영 체제와 관련하여 연속적인 바이트 시퀀스입니다. 바이트 버퍼 만 I / O 작업에 참여할 수 있다는 것은 놀라운 일이 아닙니다. 또한 운영 체제는 프로세스의 주소 공간 (이 경우 JVM 프로세스)에 직접 액세스하여 데이터를 전송합니다. 이는 I / O 펄의 대상인 메모리 영역이 연속적인 바이트 시퀀스 여야한다는 것을 의미합니다. JVM에서 바이트 배열이 연속적으로 메모리에 저장되지 않거나 가비지 콜렉터가 언제든지이를 이동할 수 있습니다. 배열은 Java의 객체이며 해당 객체에 데이터가 저장되는 방식은 JVM 구현마다 다를 수 있습니다.

이러한 이유로 직접 버퍼의 개념이 도입되었습니다. 직접 버퍼는 채널 및 기본 I / O 루틴과의 상호 작용을위한 것입니다. 바이트 코드를 운영 체제에 메모리 영역을 직접 비우거나 채우도록 지시하는 원시 코드를 사용하여 채널이 직접 또는 원시 액세스에 사용할 수있는 메모리 영역에 바이트 요소를 저장하기 위해 최선의 노력을 다합니다.

직접 바이트 버퍼는 일반적으로 I / O 작업에 가장 적합한 선택입니다. 설계 상으로는 JVM에서 사용할 수있는 가장 효율적인 I / O 메커니즘을 지원합니다. 비 직접 바이트 버퍼는 채널로 전달 될 수 있지만 성능이 저하 될 수 있습니다. 비 직접 버퍼가 기본 I / O 작업의 대상이되는 것은 일반적으로 불가능합니다. 쓰기를 위해 비 직접 ByteBuffer 객체를 채널에 전달하면 각 호출에서 채널이 암시 적으로 다음을 수행 할 수 있습니다.

  1. 임시 직접 ByteBuffer 객체를 만듭니다.
  2. 비 직접 버퍼의 내용을 임시 버퍼로 복사하십시오.
  3. 임시 버퍼를 사용하여 저수준 I / O 작업을 수행하십시오.
  4. 임시 버퍼 개체가 범위를 벗어 났으며 결국 가비지 수집됩니다.

이로 인해 잠재적으로 모든 I / O에서 버퍼 복사 및 객체 이탈이 발생할 수 있으며, 이는 바로 우리가 피하고 싶은 것들입니다. 그러나 구현에 따라 상황이 나쁘지 않을 수 있습니다. 런타임은 직접 버퍼를 캐시 및 재사용하거나 다른 영리한 트릭을 수행하여 처리량을 높일 수 있습니다. 단순히 일회용 버퍼를 만드는 경우 그 차이는 크지 않습니다. 반면, 고성능 시나리오에서 버퍼를 반복적으로 사용하는 경우 직접 버퍼를 할당하고 재사용하는 것이 좋습니다.

직접 버퍼는 I / O에 최적이지만 비 직접 바이트 버퍼보다 ​​작성 비용이 더 많이들 수 있습니다. 직접 버퍼가 사용하는 메모리는 표준 JVM 힙을 무시하고 기본 운영 체제 별 코드를 호출하여 할당됩니다. 직접 버퍼 설정 및 해제는 호스트 운영 체제 및 JVM 구현에 따라 힙 상주 버퍼보다 ​​훨씬 비쌀 수 있습니다. 직접 버퍼의 메모리 저장 영역은 표준 JVM 힙 외부에 있으므로 가비지 수집 대상이 아닙니다.

직접 버퍼와 비 직접 버퍼의 성능 트레이드 오프는 JVM, 운영 체제 및 코드 디자인에 따라 크게 달라질 수 있습니다. 힙 외부에 메모리를 할당하면 응용 프로그램이 JVM을 인식하지 못하는 추가적인 힘을받을 수 있습니다. 추가로 움직이는 부품을 사용할 때는 원하는 효과를 얻을 수 있어야합니다. 오래된 소프트웨어를 권장합니다. 먼저 작동시킨 다음 빠르게 만드십시오. 최적화에 대해 너무 걱정하지 마십시오. 정확성에 먼저 집중하십시오. JVM 구현은 버퍼 캐싱 또는 기타 최적화를 수행하여 불필요한 노력 없이도 필요한 성능을 제공 할 수 있습니다.


답변

jvm 내부 에서 액세스하기 위해 직접 버퍼가 더 빠를 것으로 예상 할 이유가 없습니다 . 모든 종류의 채널 뒤의 코드와 같은 네이티브 코드로 전달할 때 장점이 있습니다.


답변

DirectByteBuffers는 OS 수준에서 직접 메모리 매핑이기 때문에

그렇지 않습니다. 그것들은 단지 일반적인 애플리케이션 프로세스 메모리이지만 Java GC 동안 재배치되지 않아 JNI 계층 내부의 것들을 상당히 단순화시킵니다. 설명하는 내용이에 적용됩니다 MappedByteBuffer.

get / put 호출로 더 빨리 수행 할 수 있도록

결론은 전제에서 따르지 않습니다. 전제는 거짓이다. 결론도 틀 렸습니다. JNI 계층에 들어가면 속도가 빠르며, 데이터를 JNI 경계를 넘지 않아도되기 때문에 데이터를 읽고 쓰는 DirectByteBuffer경우 훨씬 빠릅니다.


답변

직접 측정하는 것이 가장 좋습니다. 빠른 대답은 크기에 따라 allocateDirect()버퍼 에서 전송하는 것이 allocate()변형에 비해 시간이 25 %에서 75 % 덜 걸리는 것 (파일을 / dev / null로 테스트 한 것으로 확인 됨)이지만 할당 자체가 상당히 느려질 수 있습니다. 100 배의 계수).

출처 :


답변