Windows sistemlerindeki büyük nesne yığını

.NET çöp toplayıcısı (GC), nesneleri küçük ve büyük nesnelere böler. Bir nesne büyük olduğunda, bazı öznitelikleri nesnenin küçük olduğundan daha önemli hale gelir. Örneğin sıkıştırmak( başka bir deyişle yığının başka bir yerine bellekte kopyalamak) pahalıya patlayabilir. Bu nedenle, çöp toplayıcı büyük nesne yığınına (LOH) büyük nesneler yerleştirir. Bu makalede, bir nesneyi büyük bir nesne olarak nitelemeyi, büyük nesnelerin nasıl toplandığını ve büyük nesnelerin ne tür performans etkilerine neden olduğu açıklanır.

Önemli

Bu makalede, yalnızca Windows sistemlerinde çalışan .NET Framework ve .NET Core'daki büyük nesne yığını ele alınmaktadır. Diğer platformlarda .NET uygulamalarında çalışan LOH'yi kapsamaz.

Bir nesnenin LOH'ta nasıl sona ermesi

Nesne boyutu 85.000 bayttan büyük veya buna eşitse, büyük bir nesne olarak kabul edilir. Bu sayı, performans ayarlaması tarafından belirlendi. Bir nesne ayırma isteği 85.000 veya daha fazla bayt için olduğunda, çalışma zamanı bunu büyük nesne yığınına ayırır.

Bunun ne anlama geldiğini anlamak için, çöp toplayıcı hakkında bazı temelleri incelemek yararlı olur.

Çöp toplayıcı bir nesil toplayıcıdır. Üç nesil vardır: 0. nesil, 1. nesil ve 2. nesil. Üç nesil olmasının nedeni, iyi ayarlanmış bir uygulamada çoğu nesnenin 0. nesilde ölmesidir. Örneğin, bir sunucu uygulamasında, istek tamamlandıktan sonra her istekle ilişkili ayırmaların ölmesi gerekir. Uçuş içi ayırma istekleri onu 1. nesile dönüştürecek ve orada ölecek. Temelde, 1. nesil, genç nesne alanları ve uzun ömürlü nesne alanları arasında bir arabellek işlevi görür.

Yeni ayrılan nesneler yeni bir nesne nesli oluşturur ve örtük olarak 0. nesil koleksiyonlardır. Ancak, büyük nesnelerse, bazen 3. nesil olarak adlandırılan büyük nesne yığınına (LOH) gider. 3. nesil, mantıksal olarak 2. neslin bir parçası olarak toplanan fiziksel bir nesildir.

Büyük nesneler yalnızca 2. nesil bir koleksiyon sırasında toplandığından 2. nesil nesnelere aittir. Bir nesil toplandığında, tüm genç nesilleri de toplanır. Örneğin, 1. nesil GC gerçekleştiğinde hem 1. nesil hem de 0 toplanır. 2. nesil GC gerçekleştiğinde de yığının tamamı toplanır. Bu nedenle, 2. nesil GC tam GC olarak da adlandırılır. Bu makale, tam GC yerine 2. nesil GC'yi ifade eder, ancak terimler birbirinin yerine değiştirilebilir.

Nesiller GC yığınının mantıksal bir görünümünü sağlar. Fiziksel olarak, nesneler yönetilen yığın segmentlerinde yaşar. Yönetilen yığın kesimi, yönetilen kod adına VirtualAlloc işlevini çağırarak GC'nin işletim sisteminden ayırdığı bir bellek öbeğidir. CLR yüklendiğinde GC iki ilk yığın kesimi ayırır: biri küçük nesneler (küçük nesne yığını veya SOH) ve biri büyük nesneler (büyük nesne yığını) için.

Daha sonra bu yönetilen yığın kesimlerine yönetilen nesneler yerleştirilerek ayırma istekleri karşılanıyor. Nesne 85.000 bayttan küçükse, SOH için kesime konur; aksi takdirde, bir LOH segmenti üzerine konur. Segmentler, üzerine daha fazla nesne ayrıldığı için işlenir (daha küçük öbekler halinde). SOH için, gc'den kurtulan nesneler yeni nesillere yükseltilir. 0. nesil bir koleksiyondan kurtulan nesneler artık 1. nesil nesneler olarak kabul edilir ve bu şekilde devam eder. Ancak, en eski nesilden hayatta kalan nesneler hala en eski nesilde olarak kabul edilir. Başka bir deyişle, 2. nesilden sağ kalanlar 2. nesil nesnelerdir; ve LOH'dan kurtulanlar LOH nesneleridir (gen2 ile toplanır).

Kullanıcı kodu yalnızca 0. kuşakta (küçük nesneler) veya LOH'da (büyük nesneler) ayırabilir. Yalnızca GC, 1. nesildeki (0. nesilden kurtulanları tanıtarak) ve 2. nesildeki (1. nesilden kalanları tanıtarak) nesneleri "ayırabilir".

Bir çöp toplama tetiklendiğinde GC canlı nesneler üzerinden izler ve bunları sıkıştırr. Ancak sıkıştırma pahalı olduğundan GC , LOH'yi süpürür ; daha sonra büyük nesne ayırma isteklerini karşılamak için yeniden kullanılabilecek boş nesneler listesi oluşturur. Bitişik ölü nesneler tek bir boş nesneye dönüştürülür.

.NET Core ve .NET Framework (.NET Framework 4.5.1 ile başlayarak), kullanıcıların loh'un bir sonraki tam engelleme GC'si sırasında sıkıştırılacağını belirtmesine olanak tanıyan özelliği içerir GCSettings.LargeObjectHeapCompactionMode . Gelecekte .NET, LOH'yi otomatik olarak sıkıştırmaya karar verebilir. Başka bir deyişle, büyük nesneleri ayırır ve taşınmadığından emin olmak isterseniz, yine de bunları sabitlemeniz gerekir.

Şekil 1'de, GC'nin ilk nesil 0 GC'nin ardından 1. nesil oluşturması ve Obj3 ölü olması Obj1 ve ilk nesil 1 GC'nin ardından Obj2Obj5 2. nesil oluşturması senaryo gösterilmektedir. Bunun ve aşağıdaki rakamların yalnızca çizim amaçlı olduğunu unutmayın; yığında ne olduğunu daha iyi göstermek için çok az nesne içerir. Gerçekte, bir GC'ye genellikle daha fazla nesne dahil edilir.

Figure 1: A gen 0 GC and a gen 1 GC
Şekil 1: 0. nesil ve 1. nesil GC.

Şekil 2'de, bunu gören Obj1 ve Obj2 ölen 2. nesil bir GC'nin ardından, GC'nin ve tarafından Obj1 kullanılan ve Obj2için ayırma isteğini karşılamak için Obj4kullanılan bitişik boş bellek alanı oluşturduğu gösterilmiştir. Ayırma isteklerini karşılamak için, segmentin sonuna kadar olan son nesneden Obj3sonraki alan da kullanılabilir.

Figure 2: After a gen 2 GC
Şekil 2: 2. nesil GC'nin ardından

Büyük nesne ayırma isteklerini karşılamak için yeterli boş alan yoksa GC ilk olarak işletim sisteminden daha fazla kesim almayı dener. Bu başarısız olursa, biraz alan boşaltma umuduyla 2. nesil GC'yi tetikler.

1. nesil veya 2. nesil GC sırasında çöp toplayıcı, üzerinde canlı nesne olmayan kesimleri VirtualFree işlevini çağırarak işletim sistemine geri gönderir. Segmentin sonuna kadar olan son canlı nesneden sonraki alan ayrıştırılır (0/1. nesil'in canlı olduğu kısa ömürlü segment dışında, çöp toplayıcının bir kısmını işlemesini sağlar çünkü uygulamanız hemen ayıracaktır). Boş alanlar sıfırlandıklarına rağmen işlenmeye devam eder. Bu da işletim sisteminin diske geri veri yazması gerekmemesi anlamına gelir.

LOH yalnızca 2. nesil GC'ler sırasında toplandığından, LOH segmenti yalnızca böyle bir GC sırasında serbest bırakılır. Şekil 3'te, çöp toplayıcının bir segmenti (segment 2) işletim sistemine geri bıraktığı ve kalan segmentlerde daha fazla alan bıraktığı bir senaryo gösterilmektedir. Büyük nesne ayırma isteklerini karşılamak için kesimin sonundaki ayrıştırma alanını kullanması gerekiyorsa, belleği yeniden işler. (commit/decommit açıklaması için VirtualAlloc.)

Figure 3: LOH after a gen 2 GC
Şekil 3: 2. nesil GC'nin ardından gelen LOH

Büyük bir nesne ne zaman toplanır?

Genel olarak, gc aşağıdaki üç koşuldan biri altında gerçekleşir:

  • Ayırma, 0. nesil veya büyük nesne eşiğini aşıyor.

    Eşik, bir neslin özelliğidir. Atık toplayıcı içine nesne ayırdığında bir nesil için bir eşik ayarlanır. Eşik aşıldığında, bu nesilde bir GC tetikler. Küçük veya büyük nesneleri ayırdığınızda, sırasıyla 0. nesil ve LOH eşiklerini kullanırsınız. Atık toplayıcı 1. ve 2. nesillere ayrıldığında eşiklerini tüketir. Bu eşikler, program çalışırken dinamik olarak ayarlanmıştır.

    Bu tipik bir durumdur; çoğu GC yönetilen yığındaki ayırmalar nedeniyle oluşur.

  • GC.Collect yöntemi çağrılır.

    Parametresiz GC.Collect() yöntem çağrılırsa veya bağımsız değişken olarak başka bir aşırı yükleme geçirilirse GC.MaxGeneration , LOH yönetilen yığının geri kalanıyla birlikte toplanır.

  • Sistem düşük bellek durumunda.

    Bu durum, atık toplayıcı işletim sisteminden yüksek bellek bildirimi aldığında oluşur. Çöp toplayıcı, 2. nesil GC yapmanın üretken olacağını düşünüyorsa, bir tane tetikler.

LOH performansının etkileri

Büyük nesne yığınındaki ayırmalar performansı aşağıdaki yollarla etkiler.

  • Ayırma maliyeti.

    CLR, verdiği her yeni nesne için belleğin temizlendiğini garanti eder. Bu, büyük bir nesnenin ayırma maliyetinin bellek temizleme (GC tetiklemediği sürece) tarafından baskın olduğu anlamına gelir. Bir bayt temizlemek için iki döngü gerekiyorsa, en küçük büyük nesneyi temizlemek için 170.000 döngü gerekir. 2 GHz makinedeki 16 MB'lık nesnenin belleğinin temizlenmesi yaklaşık 16 ms sürer. Bu oldukça büyük bir maliyet.

  • Koleksiyon maliyeti.

    LOH ve 2. nesil birlikte toplandığından, birinin eşiği aşılırsa 2. nesil bir koleksiyon tetiklenir. 2. nesil bir koleksiyon LOH nedeniyle tetikleniyorsa, 2. nesil GC'nin ardından çok daha küçük olmayabilir. 2. nesilde çok fazla veri yoksa bunun çok az etkisi vardır. Ancak 2. nesil büyükse, çok sayıda 2. nesil GC tetiklendiğinde performans sorunlarına neden olabilir. Birçok büyük nesne geçici olarak ayrılmışsa ve büyük bir SOH'niz varsa, GC'leri yaparken çok fazla zaman harcıyor olabilirsiniz. Buna ek olarak, gerçekten büyük nesneleri ayırmaya ve bırakmaya devam ederseniz ayırma maliyeti gerçekten eklenebilir.

  • Başvuru türlerine sahip dizi öğeleri.

    LOH üzerindeki çok büyük nesneler genellikle dizilerdir (gerçekten büyük bir örnek nesnesi olması çok nadirdir). Bir dizinin öğeleri başvuru bakımından zenginse, öğeler başvuru açısından zengin değilse mevcut olmayan bir maliyete neden olur. öğesi herhangi bir başvuru içermiyorsa, çöp toplayıcının diziyi hiç geçirmesi gerekmez. Örneğin, düğümleri bir ikili ağaçta depolamak için bir dizi kullanırsanız, bunu uygulamanın bir yolu, bir düğümün sağ ve sol düğümüne gerçek düğümler tarafından başvurmaktır:

    class Node
    {
       Data d;
       Node left;
       Node right;
    };
    
    Node[] binary_tr = new Node [num_nodes];
    

    Büyükse num_nodes , atık toplayıcının öğe başına en az iki başvurudan geçmesi gerekir. Alternatif bir yaklaşım, sağ ve sol düğümlerin dizinini depolamaktır:

    class Node
    {
       Data d;
       uint left_index;
       uint right_index;
    } ;
    

    Sol düğümün verilerine olarak left.dbaşvurmak yerine olarak başvurursunuz binary_tr[left_index].d. Ayrıca atık toplayıcının sol ve sağ düğüm için başvurulara bakması gerekmez.

Üç faktörden ilk ikisi genellikle üçüncü faktörden daha önemlidir. Bu nedenle, geçici nesneler ayırmak yerine yeniden kullandığınız büyük nesnelerden oluşan bir havuz ayırmanızı öneririz.

LOH için performans verilerini toplama

Belirli bir alan için performans verilerini toplamadan önce, aşağıdakileri zaten yapmış olmanız gerekir:

  1. Bu alana bakman gerektiğine dair kanıt buldum.
  2. Gördüğünüz performans sorununu açıklayacak hiçbir şey bulamadan bildiğiniz diğer alanları tükettiniz.

Belleğin ve CPU'nun temelleri hakkında daha fazla bilgi için bir çözüm bulmaya çalışmadan önce sorunu anlama blogunu inceleyin.

LOH performansıyla ilgili verileri toplamak için aşağıdaki araçları kullanabilirsiniz:

.NET CLR Bellek performans sayaçları

.NET CLR Bellek performans sayaçları genellikle performans sorunlarını araştırmada iyi bir ilk adımdır (ETW olaylarını kullanmanızı öneririz). Performans sayaçlarına bakmanın yaygın bir yolu Performans İzleyicisi (perfmon.exe) kullanmaktır. İlgilendiğiniz işlemlere yönelik ilginç sayaçları eklemek için Ekle (Ctrl + A) öğesini seçin. Performans sayacı verilerini bir günlük dosyasına kaydedebilirsiniz.

.NET CLR Bellek kategorisindeki aşağıdaki iki sayaç LOH için geçerlidir:

  • # 2. Nesil Koleksiyonlar

    İşlem başladıktan sonra 2. nesil GC'lerin oluşma sayısını görüntüler. Sayaç, 2. nesil koleksiyonun sonunda artırılır (tam çöp toplama olarak da adlandırılır). Bu sayaç, gözlemlenen son değeri görüntüler.

  • Büyük Nesne Yığını boyutu

    LOH'nin boş alan da dahil olmak üzere geçerli boyutunu bayt cinsinden görüntüler. Bu sayaç, her ayırmada değil, çöp toplamanın sonunda güncelleştirilir.

Screenshot that shows adding counters in Performance Monitor.

Ayrıca sınıfını kullanarak PerformanceCounter program aracılığıyla performans sayaçlarını sorgulayabilirsiniz. LOH için olarak ".NET CLR Bellek" ve olarak CategoryName "Büyük Nesne Yığını boyutu" CounterNamebelirtin.

PerformanceCounter performanceCounter = new()
{
    CategoryName = ".NET CLR Memory",
    CounterName = "Large Object Heap size",
    InstanceName = "<instance_name>"
};

Console.WriteLine(performanceCounter.NextValue());

Rutin test sürecinin bir parçası olarak sayaçları program aracılığıyla toplamak yaygın bir durumdur. Normal olmayan değerlerle sayaçları tespit ettiğinizde, araştırmaya yardımcı olmak için daha ayrıntılı veriler almak için diğer araçları kullanın.

Not

ETW çok daha zengin bilgiler sağladığından performans sayaçları yerine ETW olaylarını kullanmanızı öneririz.

ETW olayları

Çöp toplayıcı, yığının ne yaptığını ve nedenini anlamanıza yardımcı olmak için zengin bir ETW olayları kümesi sağlar. Aşağıdaki blog gönderileri, ETW ile GC olaylarını toplamayı ve anlamayı gösterir:

Geçici LOH ayırmalarının neden olduğu aşırı 2. nesil GC'leri tanımlamak için, GC'lerin Tetikleyici Nedeni sütununa bakın. Yalnızca geçici büyük nesneleri ayıran basit bir test için, aşağıdaki PerfView komutuyla ETW olayları hakkında bilgi toplayabilirsiniz:

perfview /GCCollectOnly /AcceptEULA /nogui collect

Sonuç şuna benzer:

Screenshot that shows ETW events in PerfView.

Gördüğünüz gibi, tüm GC'ler 2. nesil GC'lerdir ve tümü AllocLarge tarafından tetiklenir. Bu da büyük bir nesne ayırmanın bu GC'yi tetiklediği anlamına gelir. LOH Hayatta Kalma Oranı % sütununda %1 yazan bu ayırmaların geçici olduğunu biliyoruz.

Bu büyük nesneleri kimin ayırdığını size söyleyen ek ETW olayları toplayabilirsiniz. Aşağıdaki komut satırı:

perfview /GCOnly /AcceptEULA /nogui collect

yaklaşık her 100 bin ayırmada tetiklenen bir AllocationTick olayı toplar. Başka bir deyişle, büyük bir nesne her ayrıldığında bir olay tetiklenir. Daha sonra, büyük nesneleri ayıran çağrı yığınlarını gösteren GC Heap Alloc görünümlerinden birine bakabilirsiniz:

Screenshot that shows a garbage collector heap view.

Gördüğünüz gibi, bu yalnızca yönteminden büyük nesneleri ayıran çok basit bir testtir Main .

Hata ayıklayıcısı

Sahip olduğunuz tek şey bir bellek dökümüyse ve LOH'da gerçekte hangi nesnelerin olduğuna bakmanız gerekiyorsa, .NET tarafından sağlanan SoS hata ayıklayıcısı uzantısını kullanabilirsiniz.

Not

Bu bölümde belirtilen hata ayıklama komutları Windows hata ayıklayıcıları için geçerlidir.

Aşağıda LOH analizinden elde edilen örnek çıkış gösterilmektedir:

0:003> .loadby sos mscorwks
0:003> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x013e35ec
sdgeneration 1 starts at 0x013e1b6c
generation 2 starts at 0x013e1000
ephemeral segment allocation context: none
segment   begin allocated     size
0018f2d0 790d5588 790f4b38 0x0001f5b0(128432)
013e0000 013e1000 013e35f8 0x000025f8(9720)
Large object heap starts at 0x023e1000
segment   begin allocated     size
023e0000 023e1000 033db630 0x00ffa630(16754224)
033e0000 033e1000 043cdf98 0x00fecf98(16699288)
043e0000 043e1000 05368b58 0x00f87b58(16284504)
Total Size 0x2f90cc8(49876168)
------------------------------
GC Heap Size 0x2f90cc8(49876168)
0:003> !dumpheap -stat 023e1000 033db630
total 133 objects
Statistics:
MT   Count   TotalSize Class Name
001521d0       66     2081792     Free
7912273c       63     6663696 System.Byte[]
7912254c       4     8008736 System.Object[]
Total 133 objects

LOH yığın boyutu (16.754.224 + 16.699.288 + 16.284.504) = 49.738.016 bayttır. 023e1000 ve 033db630 adresleri arasında, 8.008.736 bayt bir nesne dizisi System.Object tarafından işgal edilir, 6.663.696 bayt bir nesne dizisi System.Byte tarafından kaplanmıştır ve 2.081.792 bayt boş alan tarafından işgal edilir.

Bazen hata ayıklayıcı, LOH'nin toplam boyutunun 85.000 bayttan az olduğunu gösterir. Bunun nedeni, çalışma zamanının büyük bir nesneden daha küçük olan bazı nesneleri ayırmak için LOH'yi kullanmasıdır.

LOH sıkıştırılmadığından, loh bazen parçalanma kaynağı olarak düşünülüyor. Parçalanma şu anlama gelir:

  • Yönetilen nesneler arasındaki boş alan miktarıyla gösterilen yönetilen yığının parçalanması. SoS'da !dumpheap –type Free komut, yönetilen nesneler arasındaki boş alan miktarını görüntüler.

  • olarak MEM_FREEişaretlenmiş bellek olan sanal bellek (VM) adres alanının parçalanması. Windbg'de çeşitli hata ayıklayıcı komutlarını kullanarak alabilirsiniz.

    Aşağıdaki örnekte VM alanında parçalanma gösterilmektedir:

    0:000> !address
    00000000 : 00000000 - 00010000
    Type     00000000
    Protect 00000001 PAGE_NOACCESS
    State   00010000 MEM_FREE
    Usage   RegionUsageFree
    00010000 : 00010000 - 00002000
    Type     00020000 MEM_PRIVATE
    Protect 00000004 PAGE_READWRITE
    State   00001000 MEM_COMMIT
    Usage   RegionUsageEnvironmentBlock
    00012000 : 00012000 - 0000e000
    Type     00000000
    Protect 00000001 PAGE_NOACCESS
    State   00010000 MEM_FREE
    Usage   RegionUsageFree
    … [omitted]
    -------------------- Usage SUMMARY --------------------------
    TotSize (     KB)   Pct(Tots) Pct(Busy)   Usage
    701000 (   7172) : 00.34%   20.69%   : RegionUsageIsVAD
    7de15000 ( 2062420) : 98.35%   00.00%   : RegionUsageFree
    1452000 (   20808) : 00.99%   60.02%   : RegionUsageImage
    300000 (   3072) : 00.15%   08.86%   : RegionUsageStack
    3000 (     12) : 00.00%   00.03%   : RegionUsageTeb
    381000 (   3588) : 00.17%   10.35%   : RegionUsageHeap
    0 (       0) : 00.00%   00.00%   : RegionUsagePageHeap
    1000 (       4) : 00.00%   00.01%   : RegionUsagePeb
    1000 (       4) : 00.00%   00.01%   : RegionUsageProcessParametrs
    2000 (       8) : 00.00%   00.02%   : RegionUsageEnvironmentBlock
    Tot: 7fff0000 (2097088 KB) Busy: 021db000 (34668 KB)
    
    -------------------- Type SUMMARY --------------------------
    TotSize (     KB)   Pct(Tots) Usage
    7de15000 ( 2062420) : 98.35%   : <free>
    1452000 (   20808) : 00.99%   : MEM_IMAGE
    69f000 (   6780) : 00.32%   : MEM_MAPPED
    6ea000 (   7080) : 00.34%   : MEM_PRIVATE
    
    -------------------- State SUMMARY --------------------------
    TotSize (     KB)   Pct(Tots) Usage
    1a58000 (   26976) : 01.29%   : MEM_COMMIT
    7de15000 ( 2062420) : 98.35%   : MEM_FREE
    783000 (   7692) : 00.37%   : MEM_RESERVE
    
    Largest free region: Base 01432000 - Size 707ee000 (1843128 KB)
    

Atık toplayıcının sık sık işletim sisteminden yeni yönetilen yığın kesimleri almasını ve boş olanları işletim sistemine geri bırakmasını gerektiren geçici büyük nesnelerin neden olduğu VM parçalanmalarını görmek daha yaygındır.

LOH'un VM parçalanmalarına neden olup olmadığını doğrulamak için VirtualAlloc ve VirtualFree'de bir kesme noktası ayarlayarak bunları kimin çağırdığını görebilirsiniz. Örneğin, işletim sisteminden 8 MB'tan büyük sanal bellek öbeklerini ayırmaya çalışan kişileri görmek için aşağıdaki gibi bir kesme noktası ayarlayabilirsiniz:

bp kernel32!virtualalloc "j (dwo(@esp+8)>800000) 'kb';'g'"

Bu komut hata ayıklayıcıya girer ve çağrı yığınını yalnızca VirtualAlloc 8 MB'tan (0x800000) büyük bir ayırma boyutuyla çağrıldığında gösterir.

CLR 2.0, segmentlerin (büyük ve küçük nesne yığınları dahil) sık sık alındığı ve yayımlandığı senaryolar için yararlı olabilecek VM Biriktiricisi adlı bir özellik ekledi. VM Hoarding'i belirtmek için, barındırma API'si aracılığıyla çağrılan STARTUP_HOARD_GC_VM bir başlangıç bayrağı belirtirsiniz. CLR, boş kesimleri işletim sistemine geri göndermek yerine bu kesimlerdeki belleğin kullanımdan kalkmasını sağlar ve bunları bekleme listesine alır. (CLR'nin bunu çok büyük segmentler için yapmadığını unutmayın.) CLR daha sonra yeni segment isteklerini karşılamak için bu kesimleri kullanır. Uygulamanızın bir sonraki yeni segmente ihtiyacı olduğunda CLR, yeterince büyük bir segment bulabiliyorsa bu bekleme listesindeki bir segmenti kullanır.

VM istifleme, bellek yetersiz özel durumlarını önlemek için sistemde çalışan baskın uygulamalar olan bazı sunucu uygulamaları gibi zaten edindikleri kesimleri tutmak isteyen uygulamalar için de yararlıdır.

Uygulamanızın oldukça kararlı bellek kullanımına sahip olduğundan emin olmak için bu özelliği kullanırken uygulamanızı dikkatle test etmenizi kesinlikle öneririz.