Çöp Toplama
Xamarin. Android, mono 'nın basit Üretesel atık toplayıcısı 'nıkullanır. İki oluşturma ve büyük nesne alanıile iki tür koleksiyon içeren bir işaretleme ve tarama atık toplayıcıdır:
- İkincil Koleksiyonlar (Gen0 yığını toplar)
- Ana Koleksiyonlar (gen1 ve büyük nesne alanı yığınlarını toplar).
Not
GC aracılığıyla açık koleksiyon yokluğunda . Collect () koleksiyonları yığın ayırmaya göre isteğe bağlıdır. Bu bir başvuru sayma sistemi değildir; bekleyen bir başvuru olmadığındaveya bir kapsamda çıkış yapıldığında nesneler toplanmaz. GC, küçük yığında yeni ayırmalar için belleğin tükenme durumunda çalışır. Hiçbir ayırma yoksa, çalışmaz.
Küçük koleksiyonlar, tek EAP ve sık kullanılan ve son zamanlarda ayrılan ve atılacak nesneleri toplamak için kullanılır. İkincil koleksiyonlar, her birkaç MB ayrılan nesne sonrasında gerçekleştirilir. İkincil koleksiyonlar, GC çağırarak el ile gerçekleştirilebilir . Topla (0)
Büyük koleksiyonlar pahalıdır ve daha düşüktür ve tüm ölü nesneleri geri kazanmak için kullanılır. Ana Koleksiyonlar geçerli yığın boyutu (yığını yeniden boyutlandırmadan önce) için bellek tükendiğinde gerçekleştirilir. Ana Koleksiyonlar, GC çağırarak el ile gerçekleştirilebilir . Topla () veya GC 'yi çağırarak . GC bağımsız değişkeniyle (int) toplayın. MaxGeneration.
Çapraz VM nesne koleksiyonları
Nesne türlerinin üç kategorisi vardır.
Yönetilen nesneler: Java. lang. Object , ör. System. Stringöğesinden kalıtımla almayan türler. Bunlar normalde GC tarafından toplanır.
Java nesneleri: Android çalışma zamanı VM 'sinde bulunan ancak mono VM 'de gösterilmeyen Java türleri. Bunlar bu şekilde kullanılır ve daha fazla açıklanmayacaktır. Bunlar normalde Android çalışma zamanı VM 'si tarafından toplanır.
Eş nesneler: tüm Java. lang. Object ve Java. lang. throwable alt sınıfları gibi ıjavaobject uygulayan türler. Bu türlerin örnekleri, yönetilen bir eş ve Yerel eşolmak üzere iki "halfs" vardır. Yönetilen eş, C# sınıfının bir örneğidir. Yerel eş, Android çalışma zamanı VM içindeki bir Java sınıfının örneğidir ve C# ıjavaobject. Handle özelliği yerel EŞE BIR JNI genel başvurusu içerir.
İki tür yerel eş vardır:
Çerçeve eşleri : Xamarin. Android, ör. Android. Content. Contextgibi bir şeyi bilen "normal" Java türleri.
Kullanıcı eşleri : uygulama içinde bulunan her Java. lang. Object alt sınıfı için derleme zamanında oluşturulan Android çağrılabilir sarmalayıcılar .
Xamarin. Android işleminde iki VM olduğu için, iki tür çöp koleksiyonu vardır:
- Android çalışma zamanı koleksiyonları
- Mono koleksiyonları
Android çalışma zamanı koleksiyonları normal şekilde çalışır, ancak bir desteklenmediği uyarısıyla: JNı genel başvurusu bir GC kökü olarak değerlendirilir. Sonuç olarak, bir Android çalışma zamanı VM nesnesine sahip bir JNı genel başvurusu varsa, başka bir koleksiyon için uygun olsa bile nesne toplanamaz .
Mono koleksiyonları, eğlenceye neden olur. Yönetilen nesneler normal olarak toplanır. Eş nesneler aşağıdaki işlem gerçekleştirerek toplanır:
Mono koleksiyonu için uygun olan tüm eşdüzey nesnelere JNı genel başvurusu, JNı zayıf genel başvurusuyla değiştirilmiştir.
Android çalışma zamanı VM GC 'si çağrılır. Herhangi bir yerel eş örneği toplanabilir.
(1) içinde oluşturulan JNı zayıf genel başvuruları denetlenir. Zayıf başvuru toplanmışsa, eşdüzey nesne toplanır. Zayıf başvuru toplanmıyorsa , zayıf başvuru bir JNI genel başvurusuyla değiştirilmiştir ve eşdüzey nesne toplanmaz. Note: API 14 ' te bu, öğesinden döndürülen değerin
IJavaObject.HandleBIR GC sonrasında değişebileceği anlamına gelir.
Bunların nihai sonucu, bir eşdüzey nesne örneğinin, yönetilen kod (örneğin, bir static değişkende depolanır) veya Java kodu tarafından başvurulduğu sürece canlı hale gelir. Ayrıca, yerel eşlerin yaşam süresi, yerel eş ve yönetilen eş birlikte toplanabilir olana kadar, yerel eş için bir süre içinde, ne kadar canlı olacaklarınız dışında genişletilir.
Nesne döngüleri
Eş nesneler hem Android çalışma zamanı hem de Mono VM 'leri içinde mantıksal olarak bulunur. Örneğin, bir Android. app. Activity tarafından yönetilen eş örneği, karşılık gelen bir Android. app. Activity Framework eş Java örneğine sahip olacaktır. Java. lang. Object sınıfından kalıtımla alan tüm nesnelerin, her iki VM 'de temsilleri olması beklenir.
Her iki VM 'de temsili olan tüm nesneler, yalnızca tek bir VM (örneğin,) içinde bulunan nesnelerle karşılaştırıldığında genişletilmiş yaşam süreleri olacaktır System.Collections.Generic.List<int> .
GC çağrılıyor. Xamarin. ANDROID GC 'nin bu nesneleri toplamadan önce her IKI VM tarafından başvurulmadığını güvence altına aldığından emin olunması gerekir.
Nesne ömrünü kısaltmak için Java. lang. Object. Dispose () çağrılmalıdır. Bu, genel başvuruyu boşaltarak ve bu sayede nesnelerin daha hızlı toplanmasına izin vermek için iki VM arasında nesnenin bağlantısını el ile "sunucu" olarak "bırakır".
Otomatik Koleksiyonlar
4.1.0 sürümündenbaşlayarak, Xamarin. Android bir Gref eşiği geçildiğinde otomatik olarak tam GC gerçekleştirir. Bu eşik, platform için bilinen maksimum grefs sayısının %90 ' ü 2000 (en fazla 1800) ve donanım üzerindeki 46800 grefs (maksimum 52000). Note: Xamarin. Android yalnızca Android. Runtime. JNIEnvtarafından oluşturulan grefs sayısını sayar ve işlemde oluşturulan diğer hiçbir grefs hakkında bilgi vermez. Bu yalnızcabuluşsal bir değer.
Otomatik bir koleksiyon gerçekleştirildiğinde, hata ayıklama günlüğüne aşağıdakine benzer bir ileti yazdırılır:
I/monodroid-gc(PID): 46800 outstanding GREFs. Performing a full GC!
Bunun oluşumu belirleyici değildir ve inopportune saatlerinde (ör. grafik işlemenin ortasında) oluşabilir. Bu iletiyi görürseniz, başka bir yerde açık bir koleksiyon gerçekleştirmek veya eşdüzey nesnelerin ömrünü azaltmayıdenemek isteyebilirsiniz.
GC Köprüsü seçenekleri
Xamarin. Android, Android ve Android çalışma zamanı ile saydam bellek yönetimi sağlar. Bu, mono çöp toplayıcısının GC Köprüsüolarak adlandırılan uzantısı olarak uygulanır.
GC Köprüsü, bir mono çöp toplama işlemi sırasında çalışarak, eşler arası nesnelerin Android çalışma zamanı yığını ile doğrulanmasının gerektiği şekilde rakamlarını belirler. GC Köprüsü aşağıdaki adımları uygulayarak (sırasıyla) bu belirleme yapar:
Ulaşılamaz eşdüzey nesnelerin mono başvuru grafiğini, temsil ettikleri Java nesnelerine dönüştürür.
Java GC gerçekleştirin.
Hangi nesnelerin gerçekten yoksayıldiğini doğrulayın.
Bu karmaşık işlem, alt sınıflarının Java.Lang.Object herhangi bir nesneye serbestçe başvurmasına olanak sağlar; Java nesnelerinin C# ' a bağlı olduğu tüm kısıtlamaları ortadan kaldırır. Bu karmaşıklık nedeniyle, köprü işlemi çok pahalı olabilir ve bir uygulamada belirgin duraklamalar oluşmasına neden olabilir. Uygulama önemli duraklamalar yaşıyorsa, aşağıdaki üç GC Köprüsü uygulamasından birini araştırmanız gerekir:
TARJAN - Robert TARJAN 'un algoritmasını ve geriye doğru başvuru YAYMAYıtemel alan GC köprüsünün tamamen yeni bir tasarımı. Sanal yüklerimizin altında en iyi performansa sahiptir, ancak aynı zamanda deneysel kodun daha büyük bir sürümüne sahiptir.
Yeni -orijinal kodun büyük bir fazla örneği, ikinci iki dereceden davranışın düzeltilmesi, ancak temel algoritmayı ( Kosaraju 'in kesin bağlı bileşenleri bulma algoritmasına göre) sağlar.
Eski -özgün uygulama (üç ' un en kararlı olduğunu kabul edilir). Bu, duraklamalar kabul edilebilir ise uygulamanın kullanması gereken köprüdir
GC_BRIDGE.
Hangi GC köprüsünün en iyi şekilde çalışması gerektiğini belirlemenin tek yolu, bir uygulamada denemeler yaparak çıktıyı analiz altına göre yapılır. Benchişaretlemek için verileri toplamanın iki yolu vardır:
Günlüğü etkinleştir -her GC Köprüsü seçeneği için günlük kaydını etkinleştirin ( yapılandırma bölümünde açıklandığı gibi), ardından her bir ayarda günlük çıkışlarını yakalayıp karşılaştırın. Her bir
GCseçeneğe yönelik iletileri inceleyin; özellikleGC_BRIDGEiletiler. Etkileşimli olmayan uygulamalar için 150ms 'ye kadar duraklar, ancak çok etkileşimli uygulamalar (oyunlar gibi) için 60 MS üzerinde duraklamalar bir sorundur.Köprü muhasebesini etkinleştir -köprü hesaplama, köprü işleminde yer alan her bir nesne tarafından işaret edilen nesnelerin ortalama maliyetinin görüntülenmesini sağlar. Bu bilgileri boyuta göre sıralamak, en büyük miktarda ek nesne tutan ipuçları sağlar.
Varsayılan ayar TARJAN' dir. Bir gerileme bulursanız, bu seçeneği eskiolarak ayarlamayı gerekli bulabilirsiniz. Ayrıca, TARJAN bir performans artışı oluşturmuyorsa, daha kararlı eski seçeneğini kullanmayı tercih edebilirsiniz.
GC_BRIDGEUygulamanın hangi seçeneği kullanması gerektiğini belirtmek için bridge-implementation=oldbridge-implementation=newbridge-implementation=tarjanMONO_GC_PARAMS ortam değişkenini kullanın. Bu, bir derleme eylemiyle projenize yeni bir dosya eklenerek yapılır . Örnek:
MONO_GC_PARAMS=bridge-implementation=tarjan
Daha fazla bilgi için bkz. yapılandırma.
GC 'ye yardımcı olma
GC 'nin bellek kullanımını ve toplama sürelerini azaltmaya yardımcı olmak için birden çok yol vardır.
Eş örnekleri elden atılıyor
GC 'nin bu işlemin tamamlanmamış bir görünümü vardır ve GC belleğin yetersiz olduğunu bilmez.
Örneğin, Java. lang. Object türü veya türetilmiş türün bir örneği en az 20 bayt boyutunda (bildirimde bulunulmadan değiştirilebilir, vb.). Yönetilen çağrılabilir sarmalayıcılar ek örnek üye eklemez. bu nedenle, 10 MB/bir bellek blobuna başvuran bir Android. Graphics. bit eşlem örneğiniz olduğunda XAMARIN. Android 'in GC 'si, bir 20 baytlık nesne olduğunu bılmez ve bu, 10 MB bellek etkin olan Android çalışma zamanı tarafından ayrılmış nesneler ile bağlantılı olduğunu belirleyemeyecektir.
GC'ye yardımcı olmak için sık sık gereklidir. Ne yazık ki GC. AddMemoryPressure() veGC. RemoveMemoryPressure() desteklenmiyor, bu nedenle Java tarafından ayrılan büyük bir nesne grafiğini serbest bırakmış olduğunu biliyorsanız GC'i el ile çağırmanız gerekebilir. Collect() ile GC'den Java tarafı belleğini serbest bırakmasını ister veya Java.Lang.Object alt sınıflarını açıkça atarak yönetilen çağrılabilir sarmalayıcı ile Java örneği arasındaki eşlemeyi bozabilirsiniz. Örneğin, bkz. Hata 1084.
Not
Alt sınıf örneklerinin elden uzması konusunda son derece dikkatli olmalısınız.
Bellek bozulması olasılığını en aza indirmek için çağrısında aşağıdaki yönergeleri Dispose() inceleyin.
Birden Çok İş Parçacığı Arasında Paylaşım
Java veya yönetilen örnek birden çok iş parçacığı arasında paylaşılıyorsa, d, hiç olmayacaktır. Örneğin,Typeface.Create()önbelleğe alınmış Typeface.Create() Birden çok iş parçacığı aynı bağımsız değişkenleri sağlarsa, aynı örneği elde edilir. Sonuç olarak, örneğin bir iş parçacığından ing diğer iş parçacıklarını geçersiz kılınarak örneğin başka bir iş parçacığından atılması Dispose()TypefaceArgumentException (diğerlerinin arasında) ile JNIEnv.CallVoidMethod() sonuçlanabilirsiniz.
Sınırlayıcı Java Türlerini Devre Dışı
Örnek bağlı bir Java türünde ise, örnek yönetilen koddan yeniden kullanılmayacak ve Java örneği iş parçacıkları arasında paylaşılamaz (önceki tartışmaya bakın) sürece örnek atılır. (Bu belirlemeyi yapmak zor olabilir.) Java örneği yönetilen koda bir sonraki girişte bunun için yeni bir sarmalayıcı oluşturulur.
Bu, Drawables ve diğer yoğun kaynak kullanımına sahip örnekler söz konusu olduğunda sık sık yararlıdır:
using (var d = Drawable.CreateFromPath ("path/to/filename"))
imageView.SetImageDrawable (d);
Drawable.CreateFromPath() tarafından döndüren Eş, Kullanıcı eşlerine değil Bir Çerçeve eşlerine başvuracak olduğundan yukarıdaki güvenlidir. Bloğun sonundaki çağrı, yönetilen Drawable ve Dispose()using framework usingDispose() örnekleri arasındaki ilişkiyi bozarak Java örneğinin Android çalışma zamanının ihtiyacı olduğu anda toplanabilir. Eş örnek bir Kullanıcı eşlemesine başvurulsa bu güvenli olmaz; Burada, kullanıcı eş eşine başvuramaylarını ve bu nedenle çağrının güvenli olduğunu bilmek için "dış" bilgileri kullanıyoruz.
Diğer Türler'i Elden-
Örnek, bir Java türünün bağlaması olmayan bir türe başvurursa (özel gibi), hiçbir Java kodunun söz konusu örnekte geçersiz kılınan yöntemleri çağırmayacaklarını bilmiyorsanız ActivityActivityDispose() ÇAĞıRMAYIN. Dispose()
Bunun yapilamamasi ile sonuçlastir.
Örneğin, özel bir tıklama dinleyicisi varsa:
partial class MyClickListener : Java.Lang.Object, View.IOnClickListener {
// ...
}
Java gelecekte bu örnek üzerinde yöntemler çağırmaya çalışılamayacaksa bu örneği atmamaniz gerekir:
// BAD CODE; DO NOT USE
Button b = FindViewById<Button> (Resource.Id.myButton);
using (var listener = new MyClickListener ())
b.SetOnClickListener (listener);
Özel Durumlardan Kaçınmak için Açık Denetimler Kullanma
Java.Lang.Object.Dispose aşırı yükleme yöntemini kullandıysanız, JNI içeren nesnelere dokunmayın. Bunu yapmak, kodunuzun atık toplanmış temel alınan bir Java nesnesine erişmeyi (önemli bir şekilde) denemelerini mümkün kılan bir çift atma durumu oluşturabilir. Bunu yapmak aşağıdakine benzer bir özel durum oluşturur:
System.ArgumentException: 'jobject' must not be IntPtr.Zero.
Parameter name: jobject
at Android.Runtime.JNIEnv.CallVoidMethod
Bu durum genellikle, bir nesnenin ilk atılması bir üyenin null olmasına neden olduğunda ve ardından bu null üyede sonraki bir erişim girişimi bir özel durum oluşturmaya neden olduğunda oluşur. Özellikle, nesnenin (yönetilen örneği temel alınan Java örneğine bağlar) ilk atmada geçersiz kılınmış, ancak yönetilen kod artık kullanılabilir olmadığı halde bu temel Java örneğine erişmeye çalışır (Java örnekleri ve yönetilen örnekler arasındaki eşleme hakkında daha fazla bilgi için bkz. Yönetilen Çağrılabilir Handle Sarmalayıcılar). Handle
Bu özel durumu önlemenin iyi bir yolu, yönteminize yönetilen örnek ile temel alınan Java örneği arasındaki eşlemenin hala geçerli olduğunu açıkça doğrulamaktır; diğer bir ifade, üyelerine erişmeden önce nesnenin null ( ) olup olmadığını kontrol DisposeHandleIntPtr.Zero etmektir. Örneğin, aşağıdaki yöntem Dispose bir nesneye childViews erişer:
class MyClass : Java.Lang.Object, ISomeInterface
{
protected override void Dispose (bool disposing)
{
base.Dispose (disposing);
for (int i = 0; i < this.childViews.Count; ++i)
{
// ...
}
}
}
İlk dispose geçişi geçersiz bir childViews değere neden olursa Handle döngü erişimi for bir ArgumentException atar. aşağıdaki yöntem, ilk erişimden önce açık bir null denetimi ekleyerek HandlechildViews özel durumun ortaya Dispose çıkışlarını engeller:
class MyClass : Java.Lang.Object, ISomeInterface
{
protected override void Dispose (bool disposing)
{
base.Dispose (disposing);
// Check for a null handle:
if (this.childViews.Handle == IntPtr.Zero)
return;
for (int i = 0; i < this.childViews.Count; ++i)
{
// ...
}
}
}
Başvurulan Örnekleri Azaltma
GC sırasında bir tür veya alt sınıf örneği tarandığında, örneğin başvurduğu nesne Java.Lang.Object grafı da taranır. Java.Lang.Object Nesne grafiği, "kök örneğin" başvurduğu nesne örnekleri kümesine ek olarak kök örneğin başvurulan her şeye (tekrar tekrar) sahip olur.
Aşağıdaki sınıfı düşünün:
class BadActivity : Activity {
private List<string> strings;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
strings.Value = new List<string> (
Enumerable.Range (0, 10000)
.Select(v => new string ('x', v % 1000)));
}
}
BadActivity10004 örnek (1x BadActivity , 1x strings , 1x , , 1x , string[]strings 10000x BadActivity dize örnekleri tarafından tutulacak) 10004 nesne oluşturulur ve bunların her biri örnek tarandığında BadActivity taranır.
Bunun koleksiyon sürelerinizi olumsuz etkileye neden olabilir ve bu da GC duraklama sürelerinin artmasına neden olabilir.
Kullanıcı eş örnekleri tarafından kök erişime sahip nesne graflarının boyutunu azaltarak GC'ye yardımcı olabilirsiniz. Yukarıdaki örnekte bu, Java.Lang.Object'den devralmaz ayrı bir BadActivity.strings sınıfa taşınarak yapılabilir:
class HiddenReference<T> {
static Dictionary<int, T> table = new Dictionary<int, T> ();
static int idgen = 0;
int id;
public HiddenReference ()
{
lock (table) {
id = idgen ++;
}
}
~HiddenReference ()
{
lock (table) {
table.Remove (id);
}
}
public T Value {
get { lock (table) { return table [id]; } }
set { lock (table) { table [id] = value; } }
}
}
class BetterActivity : Activity {
HiddenReference<List<string>> strings = new HiddenReference<List<string>>();
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
strings.Value = new List<string> (
Enumerable.Range (0, 10000)
.Select(v => new string ('x', v % 1000)));
}
}
Küçük Koleksiyonlar
Küçük koleksiyonlar GC çağrılarak el ile yapılabilir. Collect(0). Küçük koleksiyonlar ucuzdur (büyük koleksiyonlara kıyasla) ancak önemli bir sabit maliyeti vardır, bu nedenle bunları çok sık tetiklemek istemiyor ve birkaç milisaniyelik bir duraklama süresine sahip olması gerekir.
Uygulamanıza aynı şeyin tekrar tekrar yapılan bir "görev döngüsü" varsa, görev döngüsü sona ererse küçük bir koleksiyonu el ile gerçekleştirmeniz tavsiye edilebilir. Örnek görev döngüleri şunlardır:
- Tek bir oyun çerçevesinin işleme döngüsü.
- Verilen bir uygulama iletişim kutusuyla etkileşimin tamamı (açma, doldurma, kapatma)
- Uygulama verilerini yenilemek/eşitlemek için bir grup ağ isteği.
Ana Koleksiyonlar
Ana koleksiyonlar GC çağrılarak el ile gerçekleştirilebilir. Collect() veya .
Bunlar nadiren gerçekleştiriliyor olmalı ve 512 MB'lık bir yığın toplarken Android stili bir cihazda saniyelik duraklama süresine sahip olabilir.
Ana koleksiyonlar yalnızca şu şekilde el ile çağrılmalı:
Uzun görev döngülerinin sonunda ve uzun bir duraklamanın kullanıcıya bir sorun sunmayarak.
Geçersiz kılınan Android.App.Activity.OnLowMemory() yöntemi içinde.
Tanılama
Genel başvuruların ne zaman oluşturularak yok edildiklerini izlemek için, debug.mono.log sistem özelliğini gref ve/veya gciçermesi için ayarlayın.
Yapılandırma
Xamarin.Android atık toplayıcısı, ortam değişkeni MONO_GC_PARAMS ayarlanabilir. Ortam değişkenleri Android'in Derleme eylemi ile ayarlanmış olabilirEnvironment.
Ortam MONO_GC_PARAMS değişkeni, aşağıdaki parametrelerin virgülle ayrılmış bir listesidir:
nursery-size=nursery-sizeBüyüklük boyutunu ayarlar. Boyut bayt cinsinden belirtilir ve iki güç olmalıdır. , ve sonkmgekleri sırasıyla kilo, mega ve gigabayt belirtmek için kullanılabilir. İlk nesil (iki nesil) de bu kadarıdır. Daha büyük bir büyük olay genellikle programı hızlandıracak ancak kesinlikle daha fazla bellek kullanacak. Varsayılan varsayılan 512 kb boyutu.soft-heap-limit=soft-heap-limitUygulama için hedef maksimum yönetilen bellek tüketimi. Bellek kullanımı belirtilen değerin altında olduğunda, GC yürütme süresi (daha az koleksiyon) için iyileştirilmiştir. Bu sınırın üzerinde, GC bellek kullanımı (daha fazla koleksiyon) için iyileştirilmiştir.evacuation-threshold=evacuation-thresholdEşik eşiğini yüzde olarak ayarlar. Değerin 0 ile 100 aralığındaki bir tamsayı olması gerekir. Varsayılan değer 66'dır. Koleksiyonun tarama aşaması belirli bir yığın blok türünün doluluk oranı bu yüzdeden az olduğunu bulursa, sonraki ana koleksiyonda bu blok türü için bir kopyalama koleksiyonu yapar ve böylece doluluk yüzde 100'e yakın geri yükleniyor. 0 değeri, kapatmayı kapatmayı sağlar.bridge-implementation=bridge-implementationBu, GC performans sorunlarının ele atılmanıza yardımcı olmak için GC Köprüsü seçeneğini ayarlar. Üç olası değer vardır: eski , yeni , tarjan.bridge-require-precise-merge: Tarjan köprüsü, nadir durumlarda bir nesnenin atık haline geldikten sonra bir GC'ye toplanmalarına neden olan bir iyileştirme içerir. Bu seçenek dahil olmak, bu iyileştirmeyi devre dışı bırakarak GC'leri daha tahmin edilebilir ancak daha yavaş hale getirme.
Örneğin, GC'yi yığın boyutu sınırı 128 MB olacak şekilde yapılandırmak için, içeriğiyle derleme eylemiyle Project dosya ekleyin:
MONO_GC_PARAMS=soft-heap-limit=128m