Операційні системи виконують операції вводу / виводу на ділянках пам'яті. Ці області пам'яті, що стосується операційної системи, є суміжними послідовностями байтів. Тож не дивно, що в операціях вводу / виводу можуть брати участь лише байтові буфери. Також пам’ятайте, що операційна система буде безпосередньо отримувати доступ до адресного простору процесу, в даному випадку - процесу JVM, для передачі даних. Це означає, що області пам’яті, які є цілями переходів вводу / виводу, повинні бути суміжними послідовностями байтів. У JVM масив байтів може не зберігатися постійно в пам'яті, або колектор сміття може перемістити його в будь-який час. Масиви - це об'єкти в Java, і спосіб зберігання даних всередині цього об'єкта може змінюватись від однієї реалізації JVM до іншої.
З цієї причини було введено поняття прямого буфера. Прямі буфери призначені для взаємодії з каналами та нативними підпрограми вводу / виводу. Вони докладають максимум зусиль для зберігання елементів байта в області пам’яті, яку канал може використовувати для прямого або сировинного доступу, використовуючи нативний код, щоб повідомити операційній системі безпосередньо злити або заповнити область пам’яті.
Буфери прямого байту зазвичай є найкращим вибором для операцій вводу / виводу. За своєю конструкцією вони підтримують найефективніший механізм вводу / виводу, доступний JVM. Ненаправлені байтові буфери можуть передаватися каналам, але це може призвести до штрафу за продуктивність. Зазвичай неможливо, щоб непрямий буфер був ціллю нативного вводу / виводу. Якщо ви передаєте непрямий об'єкт ByteBuffer каналу для запису, канал може неявно робити наступне під час кожного виклику:
- Створіть тимчасовий прямий об'єкт ByteBuffer.
- Скопіюйте вміст непрямого буфера у тимчасовий буфер.
- Виконайте операцію вводу / виводу низького рівня, використовуючи тимчасовий буфер.
- Тимчасовий буферний об’єкт виходить за межі сфери і з часом збирається сміття.
Це потенційно може призвести до буферного копіювання та зменшення об'єкта на кожному вводу-виводу, що є саме тими речами, яких ми хотіли б уникати. Однак, залежно від реалізації, справи можуть бути не такими поганими. Виконання часу, ймовірно, кешуватиме та використовуватиме прямі буфери або виконувати інші хитрі трюки для підвищення пропускної здатності. Якщо ви просто створюєте буфер для одноразового використання, різниця не суттєва. З іншого боку, якщо ви будете багаторазово використовувати буфер у високоефективних сценаріях, вам краще виділити прямі буфери та повторно використовувати їх.
Прямі буфери є оптимальними для вводу / виводу, але їх може бути дорожче створити, ніж непрямі байтові буфери. Пам'ять, яка використовується прямими буферами, виділяється за допомогою переходу до нативного коду, характерного для операційної системи, минаючи стандартну купу JVM. Налаштування та вилучення прямих буферів може бути значно дорожчим, ніж буферизовані буфери, залежно від операційної системи хосту та реалізації JVM. Області зберігання пам'яті прямих буферів не підлягають збору сміття, оскільки вони знаходяться поза стандартною купою JVM.
Компроміс продуктивності використання прямих та непрямих буферів може сильно відрізнятися залежно від проекту JVM, операційної системи та коду. Виділяючи пам'ять поза грою, ви можете піддавати вашій заяві додаткові сили, про які JVM не знає. Залучаючи в рух додаткові рухомі частини, переконайтеся, що ви досягаєте бажаного ефекту. Я рекомендую максимум старого програмного забезпечення: спочатку змусьте його працювати, а потім зробити його швидким. Не надто турбуйтеся про оптимізацію передньої частини; концентруйтеся спочатку на правильності. Реалізація JVM може виконати кешування буфера або інші оптимізації, що дасть вам необхідну продуктивність без великих зайвих зусиль.