المفاهيم
هنفهم إيه؟ لما تشغّل تطبيق ، إيه اللي يحصل للكود، وإزاي الذاكرة تتدار، وليه نوع النشر أو إعدادات الأداء تفرق؟ هنمشي من إصدار المنصة وتجميع البرنامج لحد والتنضيف والنشر، مع ربط كل مصطلح بأثره على تطبيق فعلي.
قبل ما تبدأ: التطبيق برنامج شغال داخل process، والـ process مساحة تنفيذ لها موارد وذاكرة. قبل تفاصيل GC، افتكر إن بعض البيانات مؤقتة أثناء الشغل وبعض الكائنات تفضل عايشة طالما التطبيق محتاجها. لو المصطلحات جديدة، ابدأ بكارت .NET family ثم اتبع ترتيب المحور.
المصطلحات اللي تحتها خط منقّط تقدر تضغط عليها لمعرفة معناها، وترجع تكمل من نفس مكانك.
#عيلة .NET واختيار إصدار مدعومThe .NET family and support policy
قبل ما تختار framework، لازم تعرف البرنامج هيشتغل فين، وإمتى هتحتاج تعمل upgrade. تشابه الأسماء مش معناه إن التطبيقات القديمة تشتغل على الإصدار الجديد من غير تعديل.
| المنصة | الاستخدام والمنصات | قرار عملي |
|---|---|---|
| Framework 4.x | Windows؛ تطبيقات System.Web، و Web Forms، و القديمة | صيانة حسب دعم Windows والإصدار؛ الانتقال محتاج تقييم dependencies |
| .NET Core 1–3.1 | الخط المفتوح المصدر اللي اشتغل على Windows، و Linux، و macOS | الإصدارات دي انتهى دعمها |
| .NET 5+ | تكملة .NET Core باسم موحّد؛ بعض workloads زي WPF لسه Windows فقط | اختار إصدار مدعوم، مش مجرد رقم أكبر من 5 |
| .NET 10 | نازل نوفمبر 2025؛ معاه C# 14 | الدعم لحد نوفمبر 2028 |
الإصدارات الزوجية LTS بدعم 3 سنين، والفردية . سياسة STS اتوسّعت لـ 24 شهر من .NET 9. دعم .NET 8 و .NET 9 الاتنين بيخلص في نوفمبر 2026. لازم تتابع security patches كمان، مش بس الـ major version.
dotnet --info
dotnet --list-sdks
dotnet --list-runtimes
الأول بيوضح البيئة، والتاني أدوات البناء، والتالت runtimes المثبّتة. وجود مش دليل إن سيرفر تاني عنده runtime مناسب.
#من C# لـ IL: CLR و CTS و CLSFrom C# to IL: CLR, CTS and CLS
- ابدأ بدالة C# تجمع رقمين. عند بناء مشروع معتاد، مترجم C# ينتج ومعلومات عن الأنواع داخل assembly؛ الملف الناتج ليس مجرد النص الذي كتبته.
- وقت التشغيل، بيئة تدير التنفيذ والذاكرة والاستثناءات. في مسار ، تُحوَّل تعليمات الدالة إلى كود يناسب معالج الجهاز عند الحاجة.
- الترتيب المهم: كود مصدر ← بناء ينتج IL ← بيئة تشغيل ← كود معالج. Native مسار مختلف ينقل ترجمة الكود إلى وقت النشر.
علشان لغات مختلفة تشارك نفس libraries، محتاجين تمثيل موحّد للكود والأنواع. تخيّل IL تعليمات مشتركة، والـ runtime مدير التشغيل اللي بيحوّلها وينظم الموارد.
C# source
-> Roslyn compiler
-> Assembly: IL + metadata + manifest
-> Runtime loader and type system
-> JIT -> native instructions -> CPU
GC, exceptions, threading and interop
- CLR: Common Language Runtime؛ اسم بيستخدم لوصف خدمات التشغيل. CoreCLR هو runtime أساسي في الحديث، وفيه runtimes تانية حسب الـ workload.
- IL: Intermediate Language، مش تعليمات مباشر. قابلية النقل بتعتمد كمان على libraries والـ native dependencies.
- : Common Type System، قواعد تعريف الأنواع واستخدامها، زي value types و reference types.
- : Common Language Specification، جزء مشترك من القواعد علشان public تبقى قابلة للاستخدام من لغات .NET مختلفة. مثلاً unsigned types مش CLS-compliant.
[assembly: CLSCompliant(true)]
public static class InvoiceMath
{
public static decimal AddTax(decimal total) => total * 1.14m;
}
الـ attribute بيطلب من compiler يفحص الـ public API حسب CLS؛ مش بيحوّل أي native dependency لحاجة cross-platform.
#أنواع JIT التاريخية ومعناها دلوقتيClassic JIT types and their modern equivalents
سؤال أنواع تاريخي. جاوب بالأسماء التلاتة، وبعدها وضّح إن الحديث مش بيعرضهم كتلات أوضاع تختار بينهم.
| الاسم | الفكرة القديمة | دلوقتي |
|---|---|---|
| Pre-JIT | توليد native code قبل التشغيل، زي NGen في Framework | و Native بيغطّوا احتياجات مشابهة بتصميم مختلف |
| Econo-JIT | compile بسيط عند الطلب، وإمكانية رمي native code لتوفير memory | obsolete؛ مش اختيار في .NET 10 |
| Normal-JIT | compile عند أول استخدام مع الاحتفاظ بالـ native code | الفكرة الأساسية مستمرة مع tiering و |
# Alternatives: publish the same project in different modes.
dotnet publish -c Release -r linux-x64 --self-contained false
dotnet publish -c Release -r linux-x64 -p:PublishReadyToRun=true
dotnet publish -c Release -r linux-x64 -p:PublishAot=true
الأول JIT عادي، والتاني R2R، والتالت Native AOT لو المشروع والـ dependencies متوافقين. ماتتعاملش مع NGen و Native AOT كأنهم نفس implementation.
#Tiered compilation و OSR و dynamic PGOTiered compilation, OSR and dynamic PGO
لو كل method اتعملها optimization تقيل قبل أول request، startup هيتأخر. ولو كل الكود فضل بسيط، هيتأثر. الـ runtime بيوازن بينهم على مراحل.
- Tier 0 بيوفر code سريع في التوليد؛ ممكن يوفّر كود مبدئي جاهز.
- الـ runtime بيراقب الاستخدام، ويعيد compile للـ hot methods في Tier 1 بتحسينات أقوى.
- ، أو On-Stack Replacement، يقدر ينقل تنفيذ loop طويلة لكود محسّن وهي لسه شغالة.
- Dynamic بيجمع profile فعلي للـ branches والأنواع، ويستخدمه في inlining و guarded devirtualization. مفعّل افتراضياً من 8 في الإعدادات المعتادة.
<PropertyGroup>
<TieredCompilation>true</TieredCompilation>
<TieredPGO>true</TieredPGO>
</PropertyGroup>
الأول بيسمح بالمراحل، والتاني بالـ profile. دول توضيح للإعدادات، مش توصية تضيفهم لكل مشروع. مفيش عدد calls ثابت مضمون للترقية. قيس startup لوحده و steady-state لوحده؛ benchmark من أول call بس ممكن يضللك.
#JIT ولا ReadyToRun ولا Native AOT؟Choosing JIT, ReadyToRun or Native AOT
اختيار طريقة النشر مرتبط بالـ cold starts، والـ memory، والـ compatibility، مش مسابقة مين أحدث.
| Native | |||
|---|---|---|---|
| توليد الكود | وقت التشغيل | جزء كبير وقت publish، ومعاه و JIT fallback | وقت publish؛ مفيش JIT في التطبيق |
| Startup | فيه تكلفة JIT | بيقلل تكلفة البداية | غالباً مناسب جداً للـ cold start؛ قيس فعلياً |
| بعد warm-up | dynamic وتخصيص حسب التشغيل | hot code ممكن يتعمله re-JIT | مفيش dynamic JIT PGO |
| الحجم | حسب شكل النشر | غالباً أكبر بسبب IL و native code | حسب trimming والـ dependencies؛ مش أصغر دايماً |
| القيود | مرونة أعلى في dynamic code | قريب من مرونة JIT | مفيش runtime code generation؛ محتاج metadata محفوظة |
#Stack و heap: مكان التخزين مش هو نوع القيمةStack and heap: storage versus semantics
فصل قيمة عن reference بيوضح النسخ؛ فصل stack عن heap بيوضح العمر والتخزين. الاتنين مش نفس السؤال. الـ stack زي مساحة شغل للـ thread، والـ heap مساحة objects أعمارها مش مرتبطة بنداء method واحد.
public struct Quantity { public int Value; }
public sealed class OrderLine { public Quantity Quantity; }
var line = new OrderLine(); // (1)
line.Quantity.Value = 2;
var copy = line.Quantity; // (2)
copy.Value = 9;
object boxed = copy; // (3)
Console.WriteLine(line.Quantity.Value); // 2
- (1) Quantity جوه OrderLine متخزّن inline في الـ object؛ مش مستقل.
- (2) نسخ struct بينسخ القيمة. الـ ممكن يحط الـ local في register؛ مفيش وعد إن كل local على stack.
- (3) بيعمل managed object فيه نسخة من القيمة.
الـ references نفسها ممكن تبقى locals أو fields. Closures و async state machines ممكن تخلّي locals تعيش على heap. ماتختارش struct لمجرد اعتقاد إنه هيمنع أي allocation.
#GC: generations و LOH و background collectionGC generations, LOH and background collection
- طلب ينشئ قائمة مؤقتة ثم ينتهي. طول ما فيه مرجع حي للقائمة، جامع الذاكرة لازم يعتبرها قابلة للوصول ولا يسترد مساحتها.
- بعد زوال كل المراجع الحية قد تصبح القائمة قابلة للجمع، لكن توقيت الجمع ليس فور انتهاء السطر. الأجيال Gen0 وGen1 وGen2 تقسّم العمل حسب بقاء الكائنات عبر عمليات الجمع.
- لو خزّنت القائمة في حقل static بلا حاجة، تظل قابلة للوصول وقد تكبر الذاكرة. وجود لا يمنع الاحتفاظ الخاطئ بالكائنات؛ فتّش عمّن يحتفظ بالمرجع.
معظم temporary objects عمرها قصير، فجمع مساحة صغيرة كتير أرخص من فحص heap كله كل مرة. الـ GC بيبدأ من roots زي live locals، و static fields، و GC handles، ويتتبع الـ objects اللي لسه reachable.
- Small objects غالباً تبدأ في Gen0. الناجي ممكن يترقّى لـ Gen1 ثم Gen2. جمع Gen2 بيشمل الأجيال الأصغر.
- للأجسام الكبيرة، عادةً 85,000 byte أو أكتر بحجم الـ object كله. بيتجمع مع Gen2، ومش بيتعمله compaction عادةً بشكل افتراضي.
- Background GC بيعمل جزء كبير من شغل Gen2 بالتوازي مع التطبيق؛ لسه فيه pauses ومراحل stop-the-world.
- الـ GC ممكن يعمل compact وينقل objects ويحدّث references. يمنع الحركة وممكن يزيد fragmentation.
byte[] small = new byte[1024];
byte[] large = new byte[100_000];
Console.WriteLine(GC.GetGeneration(small)); // typically 0 if no GC intervenes
Console.WriteLine(GC.GetGeneration(large)); // 2: LOH is collected with Gen2
الـ output الأول ممكن يتغير لو حصل collection. دي تجربة تعليمية، مش طريقة تختبر بيها business logic. ماتناديش GC.Collect() بعد كل request؛ عالج rate والـ retention الأول.
#Server و Workstation GC و DATASServer GC, workstation GC and DATAS
خدمة عليها عالي غير desktop محتاج استجابة سلسة. Workstation مناسب لبرامج تفاعلية وموارد محدودة. Server GC بيستخدم heaps و workers متعددة لتحقيق throughput، بس ممكن يحتاج memory أكتر.
، أو Dynamic Adaptation to Application Sizes، بيكيّف server GC مع حجم الداتا طويلة العمر وضغط الشغل، وبيغيّر عدد heaps حسب الاحتياج. اتقدّم في 8 وبقى افتراضي للـ server GC من .NET 9. مش بديل عن memory limits ومش علاج لـ leak.
<PropertyGroup>
<ServerGarbageCollection>true</ServerGarbageCollection>
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
</PropertyGroup>
الأول يطلب server GC، والتاني يسمح بالـ background collection. الـ host والبيئة بيأثروا على الوضع الفعلي؛ افحص GCSettings.IsServerGC. اختبر و p99 والـ throughput والـ memory جوه نفس container limits. تفاصيل DATAS.
#Dispose و finalizers و SafeHandleDispose, finalizers and SafeHandle
بيسترجع managed memory لما ميبقاش فيه references، لكن file handle أو connection لازم يتقفل في وقت معروف. Dispose عقد للتنضيف الفوري؛ finalizer شبكة أمان غير مضمونة التوقيت ولا مضمونة وقت إغلاق الـ process.
// An inheritable owner of a managed disposable resource.
public class InvoiceFile : IDisposable
{
private bool _disposed;
private readonly FileStream _stream = File.OpenWrite("invoice.txt");
public void Write(byte[] bytes)
{
ObjectDisposedException.ThrowIf(_disposed, this); // (1)
_stream.Write(bytes);
}
public void Dispose()
{
Dispose(true); // (2)
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing) _stream.Dispose(); // (3)
_disposed = true;
}
}
using var file = new InvoiceFile(); // (4)
file.Write([65, 66]);
- (1) استخدام resource بعد إغلاقه يطلع exception واضح.
- (2) Dispose العام ينادي extensibility hook ويمنع finalization لو فيه finalizer في النوع المشتق.
- (3) Managed resources تتقفل في المسار deterministic بس؛ تكرار Dispose هنا آمن. المثال مش thread-safe.
- (4) using بيضمن Dispose عند نهاية الـ scope حتى لو حصل exception.
لو class sealed وبيملك stream بس، Dispose بسيط كفاية. ماتضيفش finalizer لمجرد إنك بتعمل implement لـ IDisposable. لو ماسك raw native handle، فضّل SafeHandle وخلي ReleaseHandle مسؤول عن تحريره؛ الـ owner يقفل SafeHandle. في pattern قديم بيمسك raw resource بنفسه، finalizer ينادي Dispose(false) من غير لمس managed objects. استخدم IAsyncDisposable و await using لما التنضيف نفسه async.
#Memory leaks و assemblies و شكل النشرMemory leaks, assemblies and deployment units
Managed leak معناه objects لسه reachable بس التطبيق مش محتاجها: cache من غير حد، و event subscription من publisher طويل العمر، و timer، أو singleton ماسك scoped service. أما native memory leak ممكن يزوّد working set من غير زيادة managed heap.
- راقب memory مع load ثابت وبعد هدوء الشغل، وميّز working set عن live managed heap.
- استخدم counters للـ rate، و Gen2، و ، وعدد collections.
- خد gcdumps في توقيتين، وقارن الأنواع والـ retention paths. عند الحاجة استخدم dump و gcroot لتتبع الـ roots.
- اصلح المالك والعمر، وبعدها أعد نفس السيناريو. جمع dump ممكن يوقف التطبيق مؤقتاً ويكشف بيانات حساسة.
# Install the diagnostic tools separately if needed.
dotnet-counters monitor --process-id 1234 --counters System.Runtime
dotnet-gcdump collect --process-id 1234 --output orders.gcdump
dotnet-gcdump report orders.gcdump
الأوامر بتراقب runtime، وتجمع managed heap graph، وتطبع report. الـ report النصي بداية؛ تحليل reference paths محتاج viewer مناسب. مرجع dotnet-gcdump.
| المصطلح | معناه |
|---|---|
| Assembly | وحدة metadata و types و manifest، غالباً dll؛ مش نفس NuGet package |
| NuGet package | حزمة توزيع ممكن تضم assemblies لأكتر من target framework، و native assets، و build targets |
| / Runtime | SDK للبناء والـ tooling؛ runtime للتشغيل، و محتاج shared framework المناسب |
| Framework-dependent | نشر أصغر يعتمد على runtime مثبت ومدعوم على السيرفر |
| Self-contained | بيضم runtime للـ والـ architecture المحددين؛ أنت مسؤول تعيد publish للـ patches |
| Managed / unmanaged | Managed بيستخدم خدمات runtime؛ unmanaged زي native library مسؤول عن قواعد memory الخاصة بيه |
Self-contained مش مرادف لـ single-file ولا Native . P/Invoke بيوصل managed code بـ native ، ومحتاج اتفاق مضبوط على types و ownership.
أسئلة الانترفيو
مفيش نتايج
راجع فهمك
ليه الاختيار ده مناسب؟ إمتى ممكن ماينفعش؟ وإيه اللي هيتغير لو الحمل زاد أو ظهر فشل؟
3.1How do .NET Framework, .NET Core and modern .NET differ?Junior
Framework هو خط Windows القديم؛ Core بدأ الخط cross-platform، و 5+ كمّله. مش كل workload بقى cross-platform، ومفيش migration مضمون بضغطة زر.
I distinguish the original Windows-only Framework from the open-source, cross-platform .NET Core line. Starting with .NET 5, that line became modern .NET, including .NET 10. For new services I normally choose a supported modern release. For an existing Framework application I first check dependencies, especially System.Web and Windows-specific components. A shared language does not make migration automatic, and workloads such as WPF remain Windows-specific.
3.2What do LTS and STS mean for a deployment decision?Junior
مدة دعم أطول، مش وعد إن مفيش bugs. اربط الاختيار بخطة upgrades والـ patches؛ 8 و .NET 9 دعمهم بينتهي نوفمبر 2026.
I use the support window to plan upgrades and security maintenance. Even-numbered releases are with three years of support; odd-numbered releases are , extended to 24 months starting with 9. .NET 10 is supported through November 2028, while .NET 8 and .NET 9 both end support in November 2026. I still install servicing updates throughout that window; choosing LTS does not remove patching responsibilities.
3.3What happens between compiling C# and executing it?Junior
Roslyn بيطلع و metadata في assembly. في مسار ، runtime يحمّل الأنواع ويحوّل methods لـ native code وقت الاحتياج.
In a normal deployment, Roslyn compiles C# into and metadata inside an assembly. The runtime loads the assembly and resolves types, then the JIT translates methods into native instructions as needed. Later calls reuse compiled code, though tiered compilation can replace it with optimized versions. I also mention that and Native move compilation work earlier, so first-call JIT is not a universal description of every deployment.
3.4What is the difference between CTS and CLS?Junior
نظام الأنواع الكامل؛ قواعد مشتركة أضيق للـ اللي هتستخدمها لغات مختلفة. C# feature مش شرط تكون مناسبة لكل لغة .
I describe as the common type system: it defines how types are declared, represented and used. is a smaller set of interoperability rules for consumed by different .NET languages. For example, an API exposing unsigned types can be valid C# without being CLS-compliant. When publishing a broadly reusable library, I can request CLS checks on its public surface instead of assuming every language supports every C# feature.
3.5Are value types always stored on the stack?Junior
لأ. Struct field في class بيعيش جواه، و بيعمل object. الـ كمان ممكن يحتفظ بـ local في register.
No. I separate value semantics from storage. A struct field is stored inline in its containing object, which may be on the managed heap. A local struct might be on a thread's stack or optimized into registers. puts a copy into a managed object, and captured or asynchronous local state may live on the heap. The useful guarantee is that ordinary value assignment copies the value, not that every struct avoids heap memory.
3.6What is an assembly, and how does it differ from a NuGet package?Junior
Assembly وحدة أنواع و metadata؛ NuGet طريقة توزيع ممكن تشمل assemblies كتير و native assets. رقم package مش لازم يطابق assembly version.
I treat an assembly as a runtime and metadata unit containing types and a manifest, usually in a . A NuGet package is a distribution unit used during restore and build. It may contain several assemblies for different target frameworks, native binaries and build assets. One package therefore does not necessarily mean one assembly. I check target-framework compatibility and transitive dependencies during package selection rather than relying only on the package name.
3.7What are Pre-JIT, Econo-JIT and Normal-JIT?Mid
دي أسماء تاريخية. اربط Pre- بـ NGen، واذكر و كحلول حديثة مختلفة؛ Econo-JIT obsolete؛ Normal-JIT أساس التنفيذ عند الطلب.
I would frame these as historical terms. Pre- meant generating native images before execution, commonly associated with NGen in Framework. Econo-JIT traded optimizations and retained code for lower memory use and is obsolete. Normal-JIT compiles methods on demand and retains native code. Modern .NET builds on that idea with tiering and dynamic . and Native address ahead-of-time compilation needs, but they are distinct technologies rather than renamed NGen modes.
3.8How do tiered compilation, OSR and dynamic PGO work together?Mid
Tiering يوازن startup مع ؛ يحسّن loop شغالة؛ يستخدم بيانات التشغيل الفعلية بدل التخمين.
I see tiered compilation as a startup- compromise. Initial code is available quickly, then hot methods are recompiled with stronger optimizations. allows a long-running loop to move into optimized code without waiting for another method call. Dynamic collects actual execution information, including frequently observed types and branches, and uses it to improve optimized code. That is why I separate cold-start measurements from warmed-up performance and avoid quoting a fixed promotion threshold.
3.9How does the generational GC decide what to collect?Mid
القرار مبني على reachability من roots، مش reference counting. Cycles لو مش reachable تتجمع عادي؛ cache rooted هيفضل موجود حتى لو مش مفيد.
The follows references from roots and reclaims objects it cannot reach; it is not reference counting, so unreachable cycles can be collected. Generations exploit the observation that many objects die young. Small usually start in Gen0, and survivors can move to Gen1 and Gen2. Older collections include younger generations. I focus on allocation rate and retained live data, because repeatedly allocating short-lived objects and retaining an unbounded cache are different problems requiring different fixes.
3.10What is the LOH and why can large buffers cause problems?Mid
بيتجمع مع Gen2، ومش عادةً compacted. التكرار يعمل pressure و fragmentation؛ pool ينفع بس له ownership واضح.
The Large Object Heap normally receives objects of at least 85,000 bytes, including overhead, and is collected with Gen2. Because it is generally not compacted by default, repeated large temporary can increase collection pressure and fragmentation. I first consider streaming or smaller buffers, then ArrayPool when measurement supports it. A pool is not free memory: it retains arrays, may return a larger array, and requires returning each rental only after all consumers finish.
3.11Does background GC mean the application never pauses?Mid
لأ؛ فيه concurrent work وفيه pauses لازمة للتنسيق. Background مش مرادف لـ server، الاتنين أبعاد مختلفة.
No. Background overlaps much of a Gen2 collection with application execution, but coordination and some collection phases still suspend managed execution. Younger collections may also occur while background work is active. I distinguish background versus blocking collection from workstation versus server GC; they describe different choices. For -sensitive services, I measure pause distributions and request tail latency under realistic memory limits rather than assuming that background collection eliminates pauses.
3.12Why do we need Dispose if .NET has garbage collection?Mid
للـ memory، و Dispose لعمر resource معروف. Dispose مش معناه إن object اتمسح من heap، ولا GC بينادي Dispose تلقائي لكل object.
I use Dispose to release resources at a predictable point, such as returning a connection or closing a file handle. reclaims managed memory on its own schedule and does not automatically call every object's Dispose method. Disposing also does not immediately remove the managed object from the heap. I use using for synchronous cleanup and await using for asynchronous cleanup, and make resource ownership explicit so a consumer does not dispose something owned elsewhere.
3.13How do SDK, runtime, self-contained and framework-dependent relate?Mid
للبناء، runtime للتشغيل. Self-contained يضم runtime لكن محتاج republish للـ patches؛ framework-dependent يعتمد على host مناسب.
The supplies the compiler and build tools; deployment hosts generally need only the appropriate runtime. A framework-dependent app relies on an installed shared runtime. A self-contained app carries a runtime for its target and architecture, which gives deployment control but makes me responsible for republishing runtime patches. I keep that separate from single-file packaging and Native . For an app, I also check that the required ASP.NET Core shared framework is available.
3.14When would you choose Native AOT over ReadyToRun or JIT?Senior
ابدأ بقياس cold start والـ memory، وبعدها dependency compatibility. فيه ومش كل ممنوع؛ الممنوع runtime code generation والـ metadata لازم تتعرف بدري.
I consider Native when cold starts, deployment footprint or memory matter enough to justify its constraints. I audit dependencies, trimming warnings, metadata and dynamic code generation, then test the published binary on the target platform. It still includes and runtime services. is a useful intermediate choice when startup matters but flexibility is needed. For long-running services, warmed-up JIT performance with dynamic may be preferable, so I benchmark the actual workload before choosing.
3.15How would you investigate a service whose memory grows continuously?Senior
قارن managed heap مع process memory، وراقب steady load. Dumps في توقيتين تبين retained types؛ root analysis يحدد المالك بدل افتراض إن بايظ.
I first distinguish working-set growth from growth in live managed objects and observe the service under a repeatable load. With dotnet-counters I inspect rate, Gen2 and behavior. I compare heap captures to identify growing types and retention paths, using a fuller dump when root analysis needs it. Common causes include unbounded caches and event subscriptions. If managed memory is stable, I investigate native allocations and mapped memory. After fixing ownership, I repeat the same load to verify the trend.
3.16When should a class have a finalizer, and why prefer SafeHandle?Senior
Finalizer مش مطلوب لكل IDisposable. صاحب raw handle ممكن يحتاج fallback، والأفضل SafeHandle يلمّ التفاصيل ويقلل أخطاء release.
I avoid adding a finalizer just because a class implements IDisposable. If it owns managed disposable objects, I dispose those deterministically. For native handles I prefer SafeHandle, which centralizes release and provides a reliable finalization fallback. A directly owned raw resource may need a finalizer, but that path must avoid managed-object dependencies and must not throw. Finalization timing is unpredictable, adds collection cost, and is not guaranteed at process exit, so it cannot replace using.
3.17What is DATAS, and does it make GC tuning unnecessary?Senior
بيكيّف server مع حجم التطبيق؛ مش GC mode تالت، ومش بيعالج retention bug. قيس container memory والـ tail .
dynamically adapts server to application size, including its long-lived data and heap needs. It became enabled by default for server GC in 9. I would start with the runtime defaults and measure , tail and memory in the actual deployment limits. It does not remove the need for capacity planning or cure leaks. A rooted cache remains rooted regardless of how effectively the collector sizes its heaps.
3.18What changes when managed code calls an unmanaged library?Senior
الحد الفاصل محتاج صحيح، و marshaling، و ownership، ومعرفة مين يحرر memory. Unsafe bugs مش هيحلها .
I check the native , parameter sizes, string encoding, calling convention and ownership rules. Marshaling may copy data, and a native function retaining a pointer requires an explicitly valid lifetime. tracks managed objects, not arbitrary native , so I wrap owned handles with SafeHandle where possible and pair allocations with the correct release function. I also check platform-specific binaries and test error paths, because a signature mismatch can corrupt memory rather than produce a useful managed exception.
اختبر نفسك
إجابات الاختبار وعلامات إكمال المحاور بتتحفظ على المتصفح ده، ومش بتتنقل لأجهزة تانية.
Which .NET 10 support statement is correct?
A struct is a field inside a managed class instance. Where is its data?
Which classic JIT type is obsolete?
What can OSR improve?
Which statement about Native AOT is correct?
Which collection includes LOH reclamation?
What does using guarantee on ordinary scope exit, including exceptions?
An unbounded static cache retains unused orders. Why can GC not free them?
Who applies runtime security updates for a self-contained deployment?
What is the best first investigation when working set grows?