Java Memory Model
برای تنظیمات حافظه در JMV یکسری دستور داریم:
-XmsSetting — initial Heap size
-XmxSetting — maximum Heap size
-XX:NewSizeSetting — new generation heap size
-XX:MaxNewSizeSetting — maximum New generation heap size
-XX:MaxPermGenSetting — maximum size of Permanent generation
-XX:SurvivorRatioSetting — new heap size ratios (e.g. if Young Gen size is 10m and memory switch is -XX:SurvivorRatio=2, then 5m will be reserved for Eden space and 2.5m each for both Survivor spaces, default value = 8)
-XX:NewRatio — providing ratio of Old/New Gen sizes (default value = 2)
JVM دقیقا مثل باقی برنامه ها یک فضا رو توی رم اشغال میکنه و خودش کامل اون رو مدیریت میکنه. ستا فضای کاملا جدا از هم داریم که JVM دادههای زمان اجرا و کدهای کامپایل شده رو اونجا نگهمیداره. به ترتیب Heap و Non-Heap و Cache.
Heap Memory
- این حافظه به دو قسمت Young Generation و Old Generation تقسیم میشه.
- این حافظه زمانی تخصیص داده میشه که JVM استارت میشه. (xms)
- اندازه این حافظه زمانی که برنامهای در حال اجراست کم و زیاد میشه.
- این حافظه تا xmx زیاد میشه
Young Generation
- این حافظه برای اشیای تازه تخصیص یافته استفاده میشه.
- این قسمت از سه بخش تشکیل شده یک Eden Memory و دوتا Survivor Memory spaces.
- تمام اشیای جدید میرن توی Eden.
- وقتی Eden پر میشه، Minor GC اجرا میشه و بعدش تمام اشیای باقی مونده رو میبره تو یکی از Survivor ها.
- Minor GC همچنین Survivorی که داده داره رو چک میکنه و بعدش اشیای باقی مونده رو میریزه تو اون یکی Survivor. این یعنی همیشه یکی از Survivor ها خالی هستش.
- اشیایی که بعد از چند بار اجرا شدن Minor GC هنوز باقی مونده باشن با توجه به سنشون اگه واجد شرایط باشن از young gen به old gen منتقل میشن.
Old Generation
- این حافظه برای اشیایی است که بعد از کلی اجرا شدن Minor GC هنوز زنده هستند.
- وقتی این حافظه پر بشه Major GC اجرا میشه که معمولا زمان زیادی هم نیاز داده.
Non-Heap Memory
- در گذشته در این حافظه Permanent Generation بوده که از جاوا ۸ به بعد با Metaspace جایگزین شده.
- perm gen به ازای هر کلاس ساختارش، متغیرهاش، ثابتهاش، دادههای متدهایش، کد متدهایش رو ذخیره میکنه
- اندازه این حافظه با XX:PermSize و XX:MaxPermSize تعیین میشه.
Cache Memory
- تو این حافظه کدهایی که JIT کامپایل کرده به همراه دادههای JVM و کدها و دادههای profiler نگهداری میشه.
- وقتی فضای این حافظه از حدش فراتر بره، داده flush میشه و این هیچ ربطی به GC نداره.
Stack vs Heap
| Stack | Heap | |
تعریف کلی | به ازای هر thread ساخته میشه و thread safe هستش. | حافظه مشترک در برنامه هستش و thread safe نیست. |
| سایز | سایزش محدود هستش و وابسته به سیستم عامله. ولی از heap کوچیکتره. | یا سایز رو برنامه قبل از اجرا مشخص میکنه یا از سایز پیش فرض استفاده میکنه. ولی سیستم عامل محدودیتی براش نداره. |
| کاربرد | فقط متغیرهای primitive توش ذخیره میشن یا رفرنس دادههایی که توی heap ساخته شدن. | همه اشیای جدید اینجا ساخته میشن. |
دسترسی | دسترسی به این حافظه به صورت FILO هستش | خیلی دسترسی به این حافظه پیچیدست چون کلی بخش مختلف داره که کارهای مختلفی انجام میدن و از کلی تکنیک برای استفاده میشه. |
| حیات | تا زمانی که thread متناظرش در حال اجراست. | تا زمانی که برنامه در حال اجراست. |
| مقایسه | در مقایسه با heap خیلی سریعتر تخصیص داده میشه. | در مقایسه با stack خیلی کندتر تخصیص داده میشه. |
تخصیص و آزاد سازی | این حافظه به صورت خودکار با ایجاد یک thread ساخته میشه و در انتها از بین میره و به ازای فراخوانی هر متد یک frame بهش اضافه میشه. | زمانی که یک شی ساخته میشه بهش فضا اختصاص میده و اگه برای مدتی کسی با اون شی کاری نداشته باشه GC اون رو حذف میکنه. |
توی ورژن آخر JVM تغییراتی داشته:
- Keep Area: یک حافظه جدید توی young gen هستش که دادههای جدید توش ساخته میشه. تا زمانی که دادهها به قسمت بعد نرن GC بهشون کاری نداره. این فضا از ارتقا اشیا فقط به خاطر اینکه اونها درست قبل از اینکه یک young collection شروع بشه تخصیص داده شدن جلوگیری میکنه.
- Metaspace: از جاوا ۸ جایگزین perm gen شده. میتونه سایز خودش رو افزایش بده در حالی که حداکثر فضا برای perm gen ثابت بود. تا زمانی که class loader زندست، metadata ها توی این فضا هستند و خالی هم نمیشن.
خطاهای مربوط به حافظه:
- StackOverFlowError: وقتی که stack پر شده باشد.
- OutOfMemoryError:
- Java heap space: وقتی که heap پر شده باشد.
- GC Overhead limit exceeded: وقتی GC به بالاترین حد پردازشی خود رسیده است.
- Permgen space: وقتی که perm gen پر شده باشد.
- Metaspace: وقتی که metaspace پر شده باشد.
- Unable to create new native thread: وقتی که تعداد زیادی native thread درست شده باشد و کل حافظه در دسترس JVM مصرف شده باشد و JVM نتونه native thread جدید درست کنه.
- Requested size bytes for reason: وقتی که برنامه ما کاملا حافظه swap رو مصرف کنه.
- Requested array size exceeds VM limit: وقتی که ما یک ارایه درست کنیم که سایزش بزرگتر از heap باشه.
اینها به این معنی نیستن که مشکلی توی JVM وجود داره. قطعا مشکل توی برنامه ماست. ولی این خطاها کمک میکنن که ما مشکل برناممون رو بهتر پیدا و حل کنیم. حل هر مشکلی مربوط به حافظه هم با افزایش حافظه حل نمیشه باید ریشه مشکل رو توی برنامه پیدا کنیم.