کد Native حاصل از اجرای برنامه های ‎.NET در کجا ذخیره میشود؟

شاید یکی دو سال قبل بنده دنبال جواب این پرسش بودم و در اینترنت جستجو و پرسش کردم اما کسی پاسخ دقیق و منبع معتبری براش نداشت. اما بر حسب اتفاق چند ماه پیش در جریان بحثی درمورد دات نت با یک شخص دیگر، ایشون منابعی و نکاتی رو مطرح کرد که تونستم توسط اونا به جواب این پرسش برسم. گفتم شاید این پرسش برای افراد دیگری هم مطرح شده باشه یا براشون بهرصورت جالب باشه که این مطلب رو بدونن. ضمنا یه خوبی درج کردن مطالبی مهمی که یاد میگیرم در این وبلاگ اینه که همشون رو برای رجوع آینده توسط خودم هم اینطوری آرشیو میکنم. بارها شده یه چیزایی رو خودم بعدها مجددا دنبالشون میگشتم که با صرف وقت و انرژی مجدد قابل توجهی اونا رو پیدا کردم یا حتی در بعضی موارد هم دیگه پیدا نکردم!!

من خودم فکر میکردم این چندان منطقی بنظر نمیاد که کد MSIL یه برنامهء دات نت در هر بار اجرا به کد Native تبدیل بشه و با خودم میگفتم خب چرا این کد Native یک بار تولید نشه و بعد برای استفاده در دفعات بعد Cache نشه؟ من فکر میکردم حتما این کدها در جایی روی هارد دیسک باید ذخیره شده باشن، که دنبال پیدا کردن مکان و روش ذخیرهء اونا بودم (احتمال میدادم که شاید بجای فایلهای عادی در دیتابیس ویژه ای یا بهرصورت به شکل خاصی که بصورت عادی نشه تشخیص داد ذخیره شده باشن)، ولی هرچی دنبالش گشتم چیزی پیدا نکردم، بنابراین واقعا گیج شده بودم! البته احتمال این رو هم میدادم که این کدها اصولا بصورت دائمی روی دیسک ذخیره نشن و مثلا فقط ممکنه درRAM و بنابراین طبیعتا تا مدتی که سیستم خاموش نشده کش ذخیره بشن یا اینکه حداقل تا زمان محدودی یا مثلا ممکنه درمورد برنامه های ASP.NET تا زمانیکه IIS در حال اجراست ذخیره باشن (در همون RAM منظورمه). آخرین حالتی که احتمالش رو میدادم این بود که این کدها یک بار مصرف باشن و فقط برای هر تک اجرای هر برنامه استفاده بشن و بعد از خاتمه اجرای برنامه دور انداخته بشن! ولی فکر میکردم این گزینه زیاد منطقی نیست چون لزومی نداره و کامپایل در هر بار اجرا یک کار تکراری بیهوده است که منابع سیستم رو هدر میده و پرفورمنس رو پایین میاره. اما جالب اینکه با بررسی منابع معتبر متوجه شدم که درواقع سیستم دات نت به همین صورته! (البته یک روش دیگر در NGen وجود داره که اونم در ادامه مطرح خواهیم کرد) اینکه چرا اینطوریه نمیدونم، اما حتما دلیل قابل قبولی داشته. بهرحال برنامه نویسان شرکتی به عظمت میکروسافت که اینقدر احمق نیستن!

خب حالا به مطرح کردن واقعیت ها از منابع موثق میپردازم.

برنامه های دات نت در حالت عادی به روش JIT اجرا میشن که در این روش کد برنامه موقع اجرا ابتدا به کد Native (زبان ماشین مقصد) کامپایل میشه و بعد اجرا میشه. میدونید که در فایلهای EXE/DLL برنامه های دات نت، کد به زبان MSIL قرار داره و نه کد اجرایی Native (زبان ماشین واقعی).
ضمنا یه نکتهء دیگه که نمیدونستم و از خوندن منابع فهمیدم این بود که موقعی که برنامه شروع به اجرا میکنه، تمامی کد برنامه از همون اول کامپایل و به کد ماشین تبدیل نمیشه، بلکه هر بخش از کد (هر متد) موقعی که در برنامه عملا فراخوانی میشه همون موقع به کد ماشین تبدیل میشه، و بنابراین بخشهایی از برنامه که ممکنه در مدت اجرای برنامه به هر دلیلی مورد استفاده قرار نگیرن هیچوقت کامپایل هم نمیشن و به این شکل از هدر رفتن زمان و منابع سیستم جلوگیری میشه. شاید بپرسید که چطور میشه بخشی از برنامه عملا اجرا نشه! اما اگر فکر کنید میبینید که در هر برنامه بطور معمول عملیات و متدها و بخشهای متعددی هست که در خیلی از اجراهای اون ممکنه اجرا نشن؛ مثلا بعلت موجود نبودن شرط و شرایط منطقی لازم در برنامه برای فراخوانی اون، عدم استفادهء کاربر از اون امکان/عملیات، و غیره. بنظرم حجم این کدها میتونه چشمگیر باشه و حتی از کدهایی که عملا اجرا میشن بیشتر باشه!
خب، بعد از اینکه کد یک متد برنامه توسط JIT به کد ماشین تبدیل شد، اون کد کامپایل شده تا پایان اجرای فعلی برنامه در حافظه باقی میمونه و در فراخوانی های بعدی اون متد این کدهای Native هستن که اجرا میشن (البته نکتهء دیگر اینکه نسخه های دیگر از اجرای برنامه نمیتونن از این کدها استفاده کنن و هر Process ایجاد شده در سیستم ولو اجرای دیگری از همون برنامه باشه فرایند JIT جداگانه خودش رو داره). طبیعتا هم که باید همینطور باشه! چون اگر نباشه که JIT فقط یک بار پردازشی افزوده برای برنامه داره و نه هیچ مزیتی! اما دقت کنید مزیت JIT وقتی مشخص میشه که متدی که کامپایل شده، یعنی در کل هرکد Native ای که توسط JIT تولید شده، بارها مورد استفاده قرار بگیره تا سرعت و بهینگی افزوده ای که این کدهای ماشین دارن بتونن در مجموع این بارها استفاده از سربار اولیهء کامپایل اونا تجاوز کنه. بنظر شخص بنده احتمالا در خیلی برنامه ها چنین شرایطی نباشه یا اونقدری زیاد نباشه که مزیت JIT بجای روشهای ساده تر مثل تفسیر مستقیم از کدمنبع توسط یک مفسر ساده یا اجرای مستقیم بایت کد بهینه تر (یا کد اجرایی مخصوص یک ماشین مجازی) محسوس باشه. مثلا در برنامه هایی که بخشهای زیادی از کد در هر اجرا به تعداد زیادی اجرا نمیشن، که من فکر میکنم خیلی از صفحات وب جزو این موارد باشن، بنابراین افزایش سرعت نباید قابل توجه باشه و شاید حتی بخاطر بار افزوده و زمانی که خود JIT مصرف میکنه حتی سرعت اونا مقداری به نسبت روشهای دیگر کمتر هم باشه. ولی در برنامه هایی که بخشهایی از کد بارها و بارها اجرا میشن، این افزایش سرعت هم به همون نسبت باید محسوس و محسوس تر بشه، که این بستگی به تعداد تکرار (خصوصا تکرار زیاد در زمان کوتاه – منظورم پشت سر هم و بدون تاخیر مثلا بخاطر عمل کاربر یا I/O و غیره) و نوع کد/عملیات انجام شده توسط کد که باعث تغییر در میزان افزایش سرعت اجرای کد Native نسبت به کد غیر Native میشه هم داره.

خب این تا اینجا درمورد JIT که روش اجرای عادی و استاندارد برنامه های دات نت است! البته ممکنه در روش اجرای پیشفرض برنامه های دات نت تغییرات قابل توجهی صورت بگیره و نمیشه روی این مطلب بصورت مطلق و برای مدت طولانی حساب کرد (حتی شاید همین الانم که من این مقاله رو مینویسم تغییراتی کرده باشه!)، چون این فناوری هنوز به نسبت جوان و در حال محک خوردن و بازخورد و تغییره و این مسائل انعطاف پذیر و نسبتا براحتی قابل تغییر هستند؛ کما اینکه مثلا در مطالب دیگری خوندم که کتابخانه ها/اسمبلی های دات نت نسخه های جدید موقعی که روی سیستم نصب میشن (منظور خود فریمورک دات نت است و نه برنامه های کاربر) توسط NGen پیشاپیش به کد ماشین کامپایل میشن تا سرعت شروع اولیهء برنامه های دات نت بالا بره (در نصب نسخه های قدیمی تر دات نت این عمل صورت نمیگرفته). پس میکروسافت بعدا به این نتیجه رسیده که بهتره این کار رو بکنه و بنظرم اینطوری کاربران و موارد استفادهء بیشتری رو بصورت بهینه تری پوشش میده. درمورد روش NGen در سطور بعدی بیشتر توضیح میدم.

خب روش دوم اجرای برنامه های دات نت استفاده از ابزاری بنام NGen است که درواقع یک برنامه با نام فایل NGen.exe رو استفاده میکنیم. ما گفتیم که JIT در هر بار اجرای یک برنامهء دات نت میاد و کدهای مورد استفاده/فراخوانی در برنامه رو به کد ماشین تبدیل میکنه. این امر مزایایی داره، که درمورد بعضی برنامه ها و شرایط میتونه خودش رو نشون بده و نه تنها نسبت به تفسیر کدمنبع یا بایت کد سرعت بیشتری ارائه بده، بلکه حتی در شرایطی به علل خاصی که توضیحش از موضوع و حوصلهء این مقاله خارجه، از سرعت اجرای برنامه هایی EXE کلاسیک که از پیش توسط یک کامپایلر (مثلا کامپایلر سی++) به کد ماشین مقصد تبدیل شدن هم سرعت بیشتری داشته باشه! اما درمورد خیلی از برنامه ها و شرایط هم ممکنه این خواص عملا نتونه مورد استفاده قرار بگیره و بجاش زمانی که خود JIT برای کامپایل مصرف میکنه به زمان شروع اولیه و بعدش در طول اجرای بخشهای مختلف برنامه اضافه شده و درحد محسوسی کندی ایجاد کنه! برای حل این مشکل و افزایش سرعت شروع و پاسخ دهی برنامه های دات نت، ما میتونیم توسط برنامهء NGen اونا رو پیشاپیش به کد Native کامپایل کنیم که دیگه موقع اجراشون نیازی به JIT نباشه. این کدهای کامپایل شده توسط NGen در دیسک بصورت پایداری ذخیره شده و در هر اجرای برنامه مورد استفاده قرار میگیرن. این کدهای تولید شده در مکانی بنام Native Image Cache روی دیسک ذخیره میشن. اگر مکان دقیقش رو میخواید، یه جایی در ‎C:\Windows\assembly\‎ هست. البته موقعی که در ویندوز این فولدر رو باز میکنید یک پوستهء گرافیکی خاص جزییات اون رو از دید شما پنهان میکنه و با فرمت خاصی اون رو نمایش میده، و بنابراین اگر میخواید تمام محتویات اون رو و به همون شکلی که واقعا هست ببینید باید مثلا از طریق خط فرمان واردش بشید یا با دستکاری در رجیستری این پوستهء گرافیکی مخصوص این پوشهء خاص رو غیرفعال کنید (روش غیرفعال کردنش از طریق رجیستری اینه که در آدرس HKEY_LOCAL_MACHINE\Software\Microsoft\Fusion یک DWORD بنام DisableCacheViewer و با مقدار 1 ایجاد کنید). فایلهای حاوی کد Native که NGen تولید کرده در یکسری فولدر تحت فولدری که اسمش با NativeImages شروع میشه در فولدر C:\Windows\assembly\‎ قرار دارن.

خب امیدوارم که از این مقاله استفاده کرده باشید! هرچند شاید این فکر به ذهن برسه که این مطلب خیلی دیر منتشر شده و مدتهاست دات نت قدم به عرصهء هستی گذاشته است، اما برای آموختن و نشر دانش هیچوقت دیر نیست. نه؟
یه چیزایی هست آدم یه زمانی دنبالشه اما بهش نمیرسه ولی بعدها بصورت تصادفی هم که شده بهشون میرسه و این مسئله برای من همیشه جالب و امیدبخش بوده که شاید براستی جوینده همیشه عاقبت یابنده باشد! این مطالب هم برای من از همین دست بود. البته من با دات نت چندان کاری نداشتم و ندارم هنوز (گرچه رفرنس کتابخانه دات نت 4 رو قبلا کامل خونده بودم) و تاحالا جدای از تست و بررسی های ساده و اولیه به این زبان برنامه ای ننوشتم، و این موضوع رو بیشتر از روی کنجکاوی و اطلاعات عمومی زمانی پیگیری میکردم اما اون زمان حتی در سایت میکروسافت هم جواب سوالات خودم رو پیدا نکردم و در نت هم چند جا که پرسیدم همه به نحو عجیبی سکوت میکردن یا حرفهای کلی و مبهم میزدن که معلوم بود جز یکسری مقالهء تکراری و کلی و تبلیغاتی چیز دیگه ای در این زمینه نخوندن.

منابع:
http://msdn.microsoft.com/en-us/library/ht8ecch6%28v=vs.90%29.aspx
http://stackoverflow.com/questions/5657566/where-can-i-find-location-of-generated-file-after-doing-ngen

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

*

شما می‌توانید از این دستورات HTML استفاده کنید: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>