در نسخههای اخیر داتنت، ویژگیهای مربوط به جمعآوری زباله (Garbage Collection یا GC) بهطور معمول بدون نیاز به دخالت توسعهدهنده فعال میشوند. این ویژگیها با هدف بهبود عملکرد در طیف گستردهای از سناریوها طراحی شدهاند. با این حال، معرفی قابلیت سازگاری پویا با اندازه برنامه (Dynamic Adaptation To Application Size یا DATAS) در .NET 9 و فعالسازی پیشفرض آن، یک استثنای قابل توجه است. اگرچه .NET 9 نسخه LTS (پشتیبانی طولانیمدت) نیست، اما بسیاری از توسعهدهندگان احتمالاً با ارتقا به .NET 10 برای اولین بار با DATAS مواجه خواهند شد.
DATAS به دلیل ماهیت خود، که لزوماً برای همه سناریوها بهینه نیست، تصمیم دشواری برای فعالسازی پیشفرض بود. این قابلیت بهطور خاص بر مدیریت حافظه در Server GC تمرکز دارد و میتواند منجر به تغییرات قابل توجهی در نمایه عملکرد (Performance Profile) و بهویژه مصرف حافظه (که اغلب کاهش مییابد) شود. در این مقاله، به بررسی DATAS، چگونگی عملکرد آن، سناریوهای هدف، و مهمتر از همه، نکاتی برای آمادگی و بهینهسازی آن برای برنامههای داتنت میپردازیم.
DATAS: هدفی متفاوت در جمعآوری زباله
ویژگیهای متداول GC معمولاً با هدف بهبود عملکرد عمومی و توان عملیاتی (Throughput) طراحی میشوند. اما DATAS ماهیت متفاوتی دارد؛ هدف اصلی آن انطباقپذیری با اندازه برنامه و حجم دادههای زنده (Live Data Size یا LDS) است.
سناریوهای هدف DATAS
DATAS بهطور خاص دو نوع سناریو را هدف قرار میدهد:
برنامههای با بار کاری متناوب (Bursty Workloads) در محیطهای با محدودیت حافظه:
- این مورد برای برنامههایی که تحت بار متغیری قرار دارند (مانند ساعات اوج و غیر اوج ترافیک) حیاتی است.
- DATAS در زمان کاهش بار کاری، اندازه هیپ (Heap Size) را بهطور فعال کاهش میدهد (Heap Retraction) و در زمان افزایش بار، آن را افزایش میدهد (Heap Growth).
- این ویژگی بهویژه برای برنامههایی که در کانتینرها یا محیطهای ارکستراسیون مانند Kubernetes (k8s) با محدودیتهای حافظه (Memory Limits) اجرا میشوند، اهمیت دارد؛ زیرا باعث میشود اندازه هیپ قابل پیشبینیتر باشد و امکان تنظیم مقادیر مناسب برای درخواست و محدودیت (Request and Limit) و استفاده بهتر از HPA (Horizontal Pod Autoscaler) فراهم شود.
برنامههای کوچک با استفاده از Server GC:
- DATAS تضمین میکند که حتی برای برنامههای کوچک (مانند یک نمونه اولیه ASP.NET Core) که از Server GC استفاده میکنند، اندازه هیپ به مقدار مورد نیاز واقعی برنامه نزدیک باشد.
تفاوتهای کلیدی با Server GC سنتی
Server GC سنتی هرگز هدفش انطباق با اندازه برنامه نبوده است. عملکرد آن عمدتاً بر اساس نرخ بقای (Survival Rate) نسلها است و تعداد هیپها را برابر با تعداد هستههای مجاز فرآیند (Process) تنظیم میکند. این امر باعث میشود اندازه هیپ بهشدت به تعداد هستههای ماشین میزبان وابسته باشد.
در مقابل، DATAS با هدف انطباق با LDS، تلاش میکند تا اندازه هیپ مشابهی را در ماشینهای با تعداد هستههای متفاوت حفظ کند. DATAS این کار را با دو مؤلفه کلیدی انجام میدهد:
- بودجه محاسبهشده از طریق DATAS (Budget Computed via DATAS یا BCD): این بودجه بر اساس LDS محاسبه میشود و یک حداکثر (Upper Bound) برای بودجه نسل صفر (Gen0 Budget) تعیین میکند.
- درصد هزینه توان عملیاتی هدف (Target Throughput Cost Percentage یا TCP): DATAS سعی میکند با تنظیم بیشتر بودجه نسل صفر، درصد زمان توقف در GC را (که تقریب مناسبی برای TCP است) در حدود یک مقدار هدف (پیشفرض: 2%) نگه دارد. اگر بار کاری سبکتر شود و درصد توقف کاهش یابد، بودجه نسل صفر کوچکتر میشود تا TCP هدف حفظ شود و در نتیجه، اندازه هیپ کاهش یابد.
💡 توجه: DATAS در ابتدا با یک هیپ (1 Heap) شروع به کار میکند و در صورت نیاز، تعداد هیپها را افزایش میدهد. این رفتار میتواند عملکرد راهاندازی (Startup Performance) را مختل کند، که یکی از دلایل مهم برای غیرفعالسازی احتمالی DATAS است.
چه زمانی DATAS برای برنامه شما مناسب نیست؟
از آنجایی که DATAS یک مبادله (Tradeoff) بین مصرف حافظه کمتر و احتمال کاهش توان عملیاتی ایجاد میکند، درک سناریوهایی که در آنها باید DATAS را غیرفعال کرد، ضروری است:
- عدم استفاده از حافظه آزاد شده: اگر از حافظه آزاد شده توسط DATAS استفادهای ندارید (مثلاً روی ماشینهای اختصاصی با منابع کافی)، فعالسازی آن توجیهی ندارد.
- عملکرد راهاندازی حیاتی است (Startup Performance is Critical): از آنجایی که DATAS همیشه با یک هیپ شروع میکند و زمان میبرد تا به تعداد هیپهای بیشتر برسد، اگر عملکرد راهاندازی برنامه شما بسیار حساس است، DATAS منجر به رگرسیون (Regression) خواهد شد.
- عدم تحمل رگرسیون توان عملیاتی: تیمهایی که میخواهند حداکثر توان عملیاتی را در ساعات اوج حفظ کنند و کمترین کندی را تحمل نمیکنند، باید DATAS را غیرفعال کنند، زیرا تقریباً همیشه منجر به کاهش توان عملیاتی میشود.
- غلبه GCهای نسل 2 (Gen2 GCs): در سناریوهایی که بیشتر GCهای نسل 2 رخ میدهند (اغلب به دلیل تخصیص بیش از حد اشیاء بزرگ موقت)، DATAS ممکن است کارایی لازم را نداشته باشد.
بهینهسازی و تنظیم DATAS (Tuning)
اگر تصمیم به استفاده از DATAS دارید اما نتایج پیشفرض مطلوب نیست، میتوانید آن را تنظیم کنید. تنظیم DATAS معمولاً بر تغییر BCD و TCP هدف متمرکز است.
تنظیمات کلیدی DATAS
| تنظیمات (Configuration) | نام محیطی (Environment Variable) | توضیح |
| غیرفعالسازی DATAS | DOTNET_GCDynamicAdaptationMode = 0 (یا disabled) | غیرفعال کردن کامل DATAS. |
| درصد رشد نسل صفر | DOTNET_GCDGen0GrowthPercent | ضریب رشد برای بودجه نسل صفر را تنظیم میکند (بهطور پیشفرض برای محاسبه BCD استفاده میشود). با افزایش این مقدار، بودجه نسل صفر افزایش یافته و تعداد GCها کاهش مییابد (و توان عملیاتی بهبود مییابد). |
| حداقل ضریب رشد نسل صفر | DOTNET_GCDGen0GrowthMinFactor | حداقل ضریب رشد (min_m) را برای بودجه نسل صفر بر اساس LDS تنظیم میکند. زمانی مفید است که بخواهید از فشردهسازی بیش از حد حافظه جلوگیری کنید. |
| TCP هدف | DOTNET_GCDTargetTCP | درصد هزینه توان عملیاتی هدف را تنظیم میکند (پیشفرض: 2%). اگر مقدار کمتری تنظیم کنید، GC برای دستیابی به آن بودجه نسل صفر را کاهش میدهد و حافظه بیشتری ذخیره میکند؛ اگر مقدار بالاتری تنظیم کنید، بودجه افزایش مییابد و توان عملیاتی بهبود مییابد. |
نکات تنظیم
- تحلیل GC Trace: برای تنظیم دقیق، نیاز به گرفتن یک GC Trace (مانند استفاده از PerfView) با و بدون DATAS دارید.
- بررسی Gen0 Budget و % Pause Time: ستونهای "Gen0 Alloc MB" و "% Pause Time" را در فازهای اوج بار کاری مقایسه کنید.
- افزایش توان عملیاتی: اگر رگرسیون توان عملیاتی مشاهده کردید (افزایش % Pause Time)، از
GCDGen0GrowthPercent برای افزایش بودجه Gen0 استفاده کنید تا فرکانس GCها کاهش یابد.
نکات تکمیلی برای توسعهدهندگان داتنت
استفاده از Workstation GC
اگر از Workstation GC استفاده میکنید، DATAS بهطور مستقیم بر شما تأثیر نمیگذارد. اما اگر دلیل استفاده شما از Workstation GC، صرفاً کاهش مصرف حافظه Server GC بوده است، ممکن است DATAS برای شما جذاب باشد. DATAS میتواند با محدود کردن مصرف حافظه (مانند Workstation GC) و در عین حال استفاده از چندین نخ (Thread) برای جمعآوری زباله (مانند Server GC)، مکثهای GC (GC Pauses) کوتاهتری را فراهم کند. در این حالت، بررسی مجدد استفاده از Server GC با DATAS توصیه میشود.
پرهیز از تنظیم GCHeapCount
اگر از کانفیگ GCHeapCount برای تنظیم دستی تعداد هیپها برای Server GC استفاده کنید، DATAS بهطور خودکار غیرفعال میشود، زیرا این کانفیگ به GC دستور میدهد که تعداد هیپها را تغییر ندهد، در حالی که تغییر تعداد هیپ یکی از مکانیسمهای کلیدی DATAS برای تنظیم عملکرد است. برای بهرهمندی از DATAS، این تنظیم را حذف کنید.
ابزارهای مشاهده و اندازهگیری
برای ارزیابی تأثیر DATAS، استفاده از ابزارهایی مانند PerfView و تحلیل GC Trace ضروری است. معیارهایی مانند Max Heap Size، % Pause Time in GC، و Promoted Size باید قبل و بعد از فعالسازی/تنظیم DATAS بررسی شوند. برای تجزیه و تحلیل دقیقتر، رویدادهای خاص DATAS (مانند SizeAdaptationTuning) که حاوی مقادیر دقیق LDS و TCP هستند، نیز در دسترس میباشند.
نتیجهگیری
DATAS یک تغییر پارادایم مهم در نحوه مدیریت حافظه توسط Server GC در داتنت است. این قابلیت پتانسیل زیادی برای بهبود کارایی در محیطهای ابری و کانتینری دارد، اما در عین حال، ممکن است برای سناریوهای با حداکثر توان عملیاتی، بهینهترین انتخاب نباشد. توسعهدهندگان داتنت باید با درک اهداف و مکانیسمهای DATAS، عملکرد برنامههای خود را پس از بهروزرسانی بررسی کنند و در صورت نیاز، با استفاده از تنظیمات معرفیشده، آن را مطابق با اهداف بهینهسازی خود، تنظیم یا غیرفعال سازند.