운영 체제는 메모리 영역에서 I / O 작업을 수행합니다. 이러한 메모리 영역은 운영 체제와 관련하여 연속적인 바이트 시퀀스입니다. 바이트 버퍼 만 I / O 작업에 참여할 수 있다는 것은 놀라운 일이 아닙니다. 또한 운영 체제는 프로세스의 주소 공간 (이 경우 JVM 프로세스)에 직접 액세스하여 데이터를 전송합니다. 이는 I / O 펄의 대상인 메모리 영역이 연속적인 바이트 시퀀스 여야한다는 것을 의미합니다. JVM에서 바이트 배열이 연속적으로 메모리에 저장되지 않거나 가비지 콜렉터가 언제든지이를 이동할 수 있습니다. 배열은 Java의 객체이며 해당 객체에 데이터가 저장되는 방식은 JVM 구현마다 다를 수 있습니다.
이러한 이유로 직접 버퍼의 개념이 도입되었습니다. 직접 버퍼는 채널 및 기본 I / O 루틴과의 상호 작용을위한 것입니다. 바이트 코드를 운영 체제에 메모리 영역을 직접 비우거나 채우도록 지시하는 원시 코드를 사용하여 채널이 직접 또는 원시 액세스에 사용할 수있는 메모리 영역에 바이트 요소를 저장하기 위해 최선의 노력을 다합니다.
직접 바이트 버퍼는 일반적으로 I / O 작업에 가장 적합한 선택입니다. 설계 상으로는 JVM에서 사용할 수있는 가장 효율적인 I / O 메커니즘을 지원합니다. 비 직접 바이트 버퍼는 채널로 전달 될 수 있지만 성능이 저하 될 수 있습니다. 비 직접 버퍼가 기본 I / O 작업의 대상이되는 것은 일반적으로 불가능합니다. 쓰기를 위해 비 직접 ByteBuffer 객체를 채널에 전달하면 각 호출에서 채널이 암시 적으로 다음을 수행 할 수 있습니다.
- 임시 직접 ByteBuffer 객체를 만듭니다.
- 비 직접 버퍼의 내용을 임시 버퍼로 복사하십시오.
- 임시 버퍼를 사용하여 저수준 I / O 작업을 수행하십시오.
- 임시 버퍼 개체가 범위를 벗어 났으며 결국 가비지 수집됩니다.
이로 인해 잠재적으로 모든 I / O에서 버퍼 복사 및 객체 이탈이 발생할 수 있으며, 이는 바로 우리가 피하고 싶은 것들입니다. 그러나 구현에 따라 상황이 나쁘지 않을 수 있습니다. 런타임은 직접 버퍼를 캐시 및 재사용하거나 다른 영리한 트릭을 수행하여 처리량을 높일 수 있습니다. 단순히 일회용 버퍼를 만드는 경우 그 차이는 크지 않습니다. 반면, 고성능 시나리오에서 버퍼를 반복적으로 사용하는 경우 직접 버퍼를 할당하고 재사용하는 것이 좋습니다.
직접 버퍼는 I / O에 최적이지만 비 직접 바이트 버퍼보다 작성 비용이 더 많이들 수 있습니다. 직접 버퍼가 사용하는 메모리는 표준 JVM 힙을 무시하고 기본 운영 체제 별 코드를 호출하여 할당됩니다. 직접 버퍼 설정 및 해제는 호스트 운영 체제 및 JVM 구현에 따라 힙 상주 버퍼보다 훨씬 비쌀 수 있습니다. 직접 버퍼의 메모리 저장 영역은 표준 JVM 힙 외부에 있으므로 가비지 수집 대상이 아닙니다.
직접 버퍼와 비 직접 버퍼의 성능 트레이드 오프는 JVM, 운영 체제 및 코드 디자인에 따라 크게 달라질 수 있습니다. 힙 외부에 메모리를 할당하면 응용 프로그램이 JVM을 인식하지 못하는 추가적인 힘을받을 수 있습니다. 추가로 움직이는 부품을 사용할 때는 원하는 효과를 얻을 수 있어야합니다. 오래된 소프트웨어를 권장합니다. 먼저 작동시킨 다음 빠르게 만드십시오. 최적화에 대해 너무 걱정하지 마십시오. 정확성에 먼저 집중하십시오. JVM 구현은 버퍼 캐싱 또는 기타 최적화를 수행하여 불필요한 노력 없이도 필요한 성능을 제공 할 수 있습니다.