در جاوا، Garbage Collector JVM حافظهی On-Heap را برای ذخیرهی اشیا مدیریت میکند. این حافظه در حین اجرای برنامه میتواند بزرگتر یا کوچکتر شود. وقتی حافظه پر شود، JVM عملیات جمعآوری زباله (Garbage Collection) را انجام میدهد و فضا برای تخصیصهای جدید آزاد میشود.
حافظهی Off-Heap خارج از حافظهی اصلی جاوا (Heap) قرار دارد و برای کارهایی استفاده میشود که به دسترسی سریعتر یا همکاری با کد بومی (Native) نیاز دارند. برای مثال، برای فراخوانی یک تابع C از یک برنامهی جاوا، آرگومانها باید در حافظهی Off-Heap باشند. چون عملیات Garbage Collection به حافظهی Off-Heap نمیرسد، شما میتوانید کنترل کنید چه زمانی و چگونه این حافظه آزاد شود.
برای تعامل با حافظهی Off-Heap میتوانید از شیء MemorySegment استفاده کنید.
هر MemorySegment با یک ناحیهی پیوسته از حافظه مرتبط است.
دو نوع Memory Segment وجود دارد:
در این آموزش نحوهی تخصیص و دسترسی به Native Segment ها را بررسی میکنیم.
---باید MemorySegment را با استفاده از یک Arena تخصیص دهید. Arena به شما امکان مدیریت چرخهی عمر (Lifecycle) Memory Segment های بومی را میدهد. هر Arena دارای یک Scope است. Scope مشخص میکند حافظهی Off-Heap مرتبط با MemorySegment چه زمانی باید آزاد شود و دیگر معتبر نباشد. یک Memory Segment زمانی قابل دسترسی است که Scope مرتبط با آن هنوز فعال یا زنده باشد.
چهار نوع Arena وجود دارد:
Arena.ofConfined(). عمر مشخص و قطعی به Memory Segment ها میدهد. این Arena از زمان ساخت تا بسته شدن فعال است.
یک Arena محدود دارای یک Thread مالک است — معمولاً همان Threadی که آن را ساخته. فقط Thread مالک میتواند به Memory Segment های تخصیصیافته در Arena محدود دسترسی داشته باشد.
اگر با Thread غیرمالک سعی کنید Arena محدود را ببندید، Exception دریافت خواهید کرد.Arena.ofShared(). Thread مالکی ندارد. چند Thread میتوانند همزمان به Memory Segment های تخصیصیافته در آن دسترسی داشته باشند.
همچنین هر Threadی میتواند Arena مشترک را ببندد و این عملیات ایمن و اتمیک (Atomic) است.Arena.ofAuto(). توسط Garbage Collector بهصورت خودکار مدیریت میشود. هر Threadی میتواند به Memory Segment های آن دسترسی داشته باشد.
فراخوانی Arena.close() روی یک Arena خودکار باعث پرتاب UnsupportedOperationException میشود.Arena.global(). ویژگی اصلی آن این است که هر Threadی میتواند به Memory Segment های تخصیصیافته با آن دسترسی داشته باشد.
علاوه بر آن، ناحیهی حافظهی Memory Segment های این Arena هرگز آزاد نمیشود. فراخوانی Arena::close روی یک Arena سراسری باعث پرتاب UnsupportedOperationException میشود.در مثال زیر، یک Memory Segment با یک Arena محدود تخصیص داده میشود و یک String در حافظهی Off-Heap مرتبط با آن ذخیره میشود:
String pattern = "********";
MemorySegment nativeString;
try (Arena arena = Arena.ofConfined()) {
// Allocate off-heap memory and copy the argument, a Java string, into off-heap memory
nativeString = arena.allocateFrom(pattern);
} // Off-heap memory is deallocated
Interface Arena از Interface SegmentAllocator ارثبری میکند. SegmentAllocator شامل متدهایی است که هم حافظهی Off-Heap تخصیص میدهند و هم دادههای جاوا را در آن کپی میکنند.
مثال بالا متد SegmentAllocator.allocateFrom(String) را فراخوانی میکند. این متد کارهای زیر را انجام میدهد:
حال ببینیم چگونه میتوان به مقدار ذخیرهشده در یک Memory Segment دسترسی پیدا کرد.
با متدهای داخل Interface MemorySegment میتوانید از Memory Segment ها بخوانید یا در آنها بنویسید.
هر کدام از این متدها یک Value Layout بهعنوان آرگومان دریافت میکنند. Value Layout لایوت حافظهی مرتبط با مقادیر انواع دادهی اولیه (مثل Primitive ها) را مدلسازی میکند.
یک Value Layout موارد زیر را رمزگذاری میکند:
برای مثال، MemorySegment.get(ValueLayout.OfByte,long) آرگومان ValueLayout.JAVA_BYTE را دریافت میکند.
// Access off-heap memory
for (int i = 0; i < s.length(); i++ ) {
IO.print((char)nativeString.get(ValueLayout.JAVA_BYTE, i));
}
ValueLayout.JAVA_BYTE ویژگیهای زیر را دارد:
ByteOrder.nativeOrder() است. این متد ترتیب بایتهای سختافزاری را که JVM روی آن اجرا میشود برمیگرداند.هنگام کار با Arena، بهترین شیوه این است که از یک عبارت try-with-resources استفاده کنید.
try (Arena arena = Arena.ofConfined()) {
// Allocate off-heap memory etc
} // Off-heap memory is deallocated
در مثال بالا، Scope Arena پس از خروج از عبارت try-with-resources دیگر فعال نیست.
همهی Memory Segment های مرتبط با آن Scope نامعتبر شده و نواحی حافظهی پشتیبان آنها آزاد میشوند.
اگر سعی کنید به یک Memory Segment مرتبط با Scope بستهشدهی Arena دسترسی پیدا کنید، IllegalStateException دریافت خواهید کرد.
میتوانید این مورد را با اجرای عبارت زیر در یک نشست jshell بررسی کنید:
String pattern = "********";
MemorySegment nativeString;
try (Arena arena = Arena.ofConfined()) {
nativeString = arena.allocateFrom(pattern);
}
for (int i = 0; i < s.length(); i++ ) {
// Exception in thread "main" java.lang.IllegalStateException: Already closed
IO.print((char)nativeString.get(ValueLayout.JAVA_BYTE, i));
}
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/