ماشین مجازی جاوا (JVM – Java Virtual Machine) یک ماشین مجازی است، یعنی یک رایانهٔ انتزاعی که دارای معماری مجموعهدستورالعمل خاص خود، حافظه، پشته، هیپ و… میباشد. این ماشین روی سیستمعامل میزبان اجرا میشود و درخواستهای خود برای منابع را از طریق آن مطرح میکند.
ماشین مجازی جاوا (JVM) یک مشخصه (Specification) است و میتواند پیادهسازیهای متفاوتی داشته باشد، به شرطی که این پیادهسازیها مطابق با مشخصات تعیینشده باشند.اوراکل (Oracle) پیادهسازی مخصوص به خود از JVM را دارد که به آن HotSpot JVM گفته میشود، شرکت IBM نیز پیادهسازی مخصوص به خود را دارد (مانند J9 JVM).
عملیات تعریفشده درون این مشخصات در ادامه آمده است (منبع: مشخصات JVM اوراکل).
- فرمت فایل ‘class’
- نوعهای داده
- نوعها و مقادیر ابتدایی (Primitive)
- نوعها و مقادیر ارجاعی (Reference)
- ناحیههای دادهای زمان اجرا
- فریمها (Frames)
- نمایش اشیاء (Objects)
- محاسبات ممیز شناور (Floating-point arithmetic)
- متدهای ویژه (Special methods)
- استثناها (Exceptions)
- خلاصه مجموعه دستورالعملها (Instruction set summary)
- کتابخانههای کلاس
- طراحی عمومی، پیادهسازی خصوصی
- معماری JVM (ماشین مجازی جاوا)
معماری HotSpot JVM در تصویر زیر نمایش داده شده است

موتور اجرا (Execution Engine) شامل جمعآوری زباله (Garbage Collector) و کامپایلر JIT (Just-In-Time) است. JVM در دو نوع ارائه میشود: کلاینت (Client) و سرور (Server). هر دوی این نسخهها از یک کد زمان اجرا (Runtime Code) استفاده میکنند، اما در نوع کامپایلر JIT تفاوت دارند. ما بعداً بیشتر درباره این موضوع خواهیم آموخت. کاربر میتواند نوع JVM مورد استفاده را با تعیین فلگهای JVM به صورت -client یا -server مشخص کند. JVM سرور برای اجرای طولانیمدت برنامههای جاوا روی سرورها طراحی شده است.
JVM در نسخههای ۳۲ بیتی (32b) و ۶۴ بیتی (64b) ارائه میشود. کاربر میتواند نسخه مورد نظر را با استفاده از آرگومانهای VM به صورت -d32 یا -d64 مشخص کند. نسخه ۳۲ بیتی تنها میتواند تا ۴ گیگابایت حافظه را آدرسدهی کند. با توجه به اینکه برنامههای حساس نیاز دارند دادههای حجیم را در حافظه نگهداری کنند، نسخه ۶۴ بیتی این نیاز را برطرف میسازد.
اجزای معماری JVM (ماشین مجازی جاوا)
اجزای اصلی معماری JVM (Java Virtual Machine) به شرح زیر هستند:
1. لودر کلاس (Class Loader)
JVM فرآیند بارگذاری (Loading)، پیوند (Linking) و مقداردهی اولیه (Initializing) کلاسها و رابطها را بهصورت پویا مدیریت میکند. در طی فرآیند بارگذاری، JVM نمایش باینری یک کلاس را پیدا کرده و آن را ایجاد میکند.
در فرآیند پیوند، کلاسهای بارگذاریشده با وضعیت زمان اجرای JVM ترکیب میشوند تا در مرحله مقداردهی اولیه قابل اجرا باشند. JVM اساساً برای فرآیند پیوند، از جدول نماد (Symbol Table) ذخیرهشده در استخر ثابت زمان اجرا (Run-time Constant Pool) استفاده میکند. مقداردهی اولیه شامل اجرای واقعی کلاسهای پیوندی است.
انواع لودرهای کلاس به شرح زیر هستند:
لودر کلاس BootStrap
این لودر کلاس در بالاترین سطح سلسلهمراتب لودرهای کلاس قرار دارد. این لودر، کلاسهای استاندارد JDK را از پوشه lib موجود در JRE بارگذاری میکند.
لودر کلاس Extension
این لودر کلاس در وسط سلسلهمراتب لودرهای کلاس قرار دارد و فرزند مستقیم لودر کلاس BootStrap است. این لودر کلاسهایی را که در پوشه lib\ext موجود در JRE قرار دارند بارگذاری میکند.
لودر کلاس Application
این لودر کلاس در پایینترین سطح سلسلهمراتب لودرهای کلاس قرار دارد و فرزند مستقیم لودر کلاس Extension است. این لودر، فایلهای jar و کلاسهایی را که توسط متغیر محیطی CLASSPATH مشخص شدهاند بارگذاری میکند.
2. پیوند (Linking) و مقداردهی اولیه (Initialization)
فرآیند پیوند شامل سه مرحله زیر است:
-
تأیید (Verification) − این مرحله توسط تأییدگر بایتکد (Bytecode Verifier) انجام میشود تا اطمینان حاصل شود که فایلهای
.classتولیدشده (یعنی بایتکدها) معتبر هستند. در صورت نامعتبر بودن، خطا داده شده و فرآیند پیوند متوقف میشود. -
آمادهسازی (Preparation) − در این مرحله، حافظه به تمام متغیرهای استاتیک کلاس تخصیص داده میشود و با مقادیر پیشفرض مقداردهی اولیه میشوند.
-
حلوفصل (Resolution) − در این مرحله، تمام ارجاعات حافظهای نمادین با ارجاعات اصلی جایگزین میشوند. برای این منظور، از جدول نماد (Symbol Table) موجود در حافظه ثابت زمان اجرا (Run-time Constant Memory) در ناحیه متدهای کلاس استفاده میشود.
مقداردهی اولیه (Initialization) مرحله نهایی فرآیند بارگذاری کلاس است. در این مرحله، متغیرهای استاتیک با مقادیر اصلی مقداردهی میشوند و بلوکهای استاتیک اجرا میشوند.
3. ناحیههای دادهای زمان اجرا (Runtime Data Areas)
مشخصات JVM ناحیههای دادهای خاصی را در زمان اجرا تعریف میکند که در حین اجرای برنامه مورد نیاز هستند. برخی از این نواحی هنگام شروع JVM ایجاد میشوند و برخی دیگر محلی برای تردها هستند و تنها زمانی ایجاد میشوند که یک ترد ایجاد شده و با پایان ترد، از بین میروند. این نواحی عبارتند از:
ثبات شمارنده برنامه (PC – Program Counter Register)
این ثبات محلی برای هر ترد است و آدرس دستور JVM که ترد در حال حاضر در حال اجرای آن است را نگه میدارد.
پشته (Stack)
پشته محلی برای هر ترد است و پارامترها، متغیرهای محلی و آدرسهای بازگشتی را هنگام فراخوانی متدها نگهداری میکند. اگر یک ترد بیش از حد مجاز فضا از پشته درخواست کند، خطای StackOverflow رخ میدهد. حتی اگر پشته قابلیت گسترش پویا داشته باشد، ممکن است خطای OutOfMemoryError نیز رخ دهد.
هیپ (Heap)
هیپ میان تمام تردها به اشتراک گذاشته میشود و شامل اشیاء، فراداده کلاسها، آرایهها و… است که در زمان اجرا ایجاد میشوند. هیپ هنگام شروع JVM ایجاد شده و هنگام خاموش شدن JVM از بین میرود. میتوان با استفاده از فلگهای خاصی، مقدار حافظه هیپ مورد نیاز JVM را از سیستمعامل کنترل کرد (در ادامه بیشتر درباره آن توضیح داده میشود). باید دقت شود که حافظه خیلی کم یا خیلی زیاد درخواست نشود، زیرا این موضوع تأثیر مهمی بر عملکرد برنامه دارد. همچنین، جمعآورنده زباله (GC) این فضا را مدیریت میکند و به طور مداوم اشیاء مرده را حذف کرده تا فضا آزاد شود.
ناحیه متد (Method Area)
این ناحیه در زمان اجرا برای تمام تردها مشترک است و هنگام راهاندازی JVM ایجاد میشود. این ناحیه ساختارهای مربوط به هر کلاس مانند استخر ثابت (constant pool)، کد سازندهها و متدها، دادههای متد و… را ذخیره میکند. مشخصات زبان جاوا (JLS) الزامی برای جمعآوری زباله (Garbage Collection) در این ناحیه تعیین نکردهاند؛ بنابراین پیادهسازیهای JVM میتوانند تصمیم بگیرند که GC را در این ناحیه انجام دهند یا خیر. همچنین، این ناحیه ممکن است متناسب با نیاز برنامه گسترش یابد یا نیابد؛ JLS در این مورد هم اجبار خاصی ندارد.
استخر ثابت زمان اجرا (Run-Time Constant Pool)
JVM یک ساختار دادهای خاص به ازای هر کلاس/هر نوع تعریف میکند که بهعنوان جدول نماد (Symbol Table) هنگام پیوند کلاسهای بارگذاریشده عمل میکند (و البته نقشهای دیگری نیز دارد).
پشتههای متد بومی (Native Method Stacks)
هنگامی که یک ترد متد بومی (Native Method) را فراخوانی میکند، وارد دنیای جدیدی میشود که در آن ساختارها و محدودیتهای امنیتی ماشین مجازی جاوا دیگر مانعی برای عملکرد آن نیستند. یک متد بومی معمولاً میتواند به نواحی دادهای زمان اجرای ماشین مجازی دسترسی پیدا کند (بسته به رابط متد بومی – Native Method Interface)، اما همچنین میتواند هر کار دیگری انجام دهد.
۴. موتور اجرا (Execution Engine)
موتور اجرا مسئول اجرای بایتکد است و از سه بخش مختلف تشکیل شده است:
جمعآوری زباله (Garbage Collection)
JVM چرخه حیات کامل اشیاء را در جاوا مدیریت میکند. پس از ایجاد یک شیء، توسعهدهنده دیگر نیازی به مدیریت آن ندارد. زمانی که شیء بدون مرجع باقی میماند (یعنی هیچ اشارهگری به آن وجود ندارد)، جمعآور زباله (GC) آن را از هیپ حذف میکند. این کار توسط یکی از الگوریتمهای مختلف مانند Serial GC، CMS، یا G1 انجام میشود.
نکته: در طی فرآیند GC، اشیاء در حافظه جابجا میشوند؛ بنابراین در حین اجرای GC، اشیاء غیرقابل استفاده هستند. در این مدت، کل برنامه متوقف میشود که به آن توقف “Stop-the-world” میگویند و این یک هزینه بالا برای عملکرد محسوب میشود. هدف اصلی الگوریتمهای GC کاهش زمان این توقفهاست.
مفسر (Interpreter)
مفسر بایتکد را تفسیر میکند. فرآیند تفسیر سریع انجام میشود، اما اجرای آن کند است.
کامپایلر JIT
JIT مخفف Just-In-Time است. این کامپایلر یکی از اجزای اصلی محیط اجرایی جاوا است و در زمان اجرا، بایتکد را به کد ماشین تبدیل میکند.
۵. رابط بومی جاوا (Java Native Interface – JNI)
رابط JNI با کتابخانههای متد بومی تعامل دارد که برای اجرای برنامه ضروری هستند.
۶. کتابخانههای متد بومی (Native Method Libraries)
این کتابخانهها مجموعهای از کتابخانههای C و ++C هستند که بهصورت بومی نوشته شدهاند و برای اجرای برنامههای جاوا حیاتی میباشند.



