Atık Toplama
Xamarin.Android, Mono'nun Basit Nesil çöp toplayıcısını kullanır. Bu, iki nesil ve iki tür koleksiyon içeren büyük bir nesne alanı olan bir işaretleme ve süpürme çöp toplayıcıdır:
- Küçük koleksiyonlar (0. Nesil yığınını toplar)
- Ana koleksiyonlar (1. Nesil ve büyük nesne alanı yığınlarını toplar).
Not
GC aracılığıyla açık bir koleksiyonun olmaması halinde. Collect() koleksiyonları , yığın ayırmalarına bağlı olarak isteğe bağlıdır. Bu bir başvuru sayma sistemi değildir; bekleyen başvurular olmadığı veya bir kapsamdan çıkıldığında nesneler toplanmaz. Gc, ikincil yığında yeni ayırmalar için bellek yetersiz olduğunda çalışır. Ayırma yoksa çalışmaz.
Küçük koleksiyonlar ucuz ve sıktır ve yakın zamanda ayrılan ve kullanılmayan nesneleri toplamak için kullanılır. Küçük koleksiyonlar, ayrılan her birkaç MB nesneden sonra gerçekleştirilir. İkincil koleksiyonlar GC çağrılarak el ile gerçekleştirilebilir. Topla (0)
Büyük koleksiyonlar pahalı ve daha az sıklıktadır ve tüm ölü nesneleri geri kazanmak için kullanılır. Geçerli yığın boyutu için bellek tükendiğinde (yığını yeniden boyutlandırmadan önce) ana koleksiyonlar gerçekleştirilir. Ana koleksiyonlar GC çağrılarak el ile gerçekleştirilebilir. Toplama () veya GC çağırarak. GC bağımsız değişkeniyle (int) toplayın. MaxGeneration.
VM'ler Arası Nesne Koleksiyonları
Nesne türlerinin üç kategorisi vardır.
Yönetilen nesneler: Java.Lang.Object'ten devralmayantürler, örneğin System.String. Bunlar gc tarafından normal olarak toplanır.
Java nesneleri: Android çalışma zamanı VM'sinde bulunan ancak Mono VM'ye sunulmayan Java türleri. Bunlar sıkıcı ve daha fazla tartışılmayacaktır. Bunlar normalde Android çalışma zamanı VM'sinde toplanır.
Eş nesneleri: Tüm Java.Lang.Object ve Java.Lang.Throwable alt sınıfları gibi IJavaObject uygulayan türler. Bu türlerin örneklerinin yönetilen eş ve yerel eş olmak üzere iki "yarısı" vardır. Yönetilen eş, C# sınıfının bir örneğidir. Yerel eş, Android çalışma zamanı VM'sinde bir Java sınıfının örneğidir ve C# IJavaObject.Handle özelliği yerel eşe yönelik bir JNI genel başvurusu içerir.
İki tür yerel eş vardır:
Çerçeve eşleri : Xamarin.Android hakkında hiçbir şey bilmeyen "Normal" Java türleri, örneğin android.content.Context.
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ılabilen Sarmalayıcılar .
Xamarin.Android işlemi içinde iki VM olduğundan, iki tür çöp toplama vardır:
- Android çalışma zamanı koleksiyonları
- Mono koleksiyonlar
Android çalışma zamanı koleksiyonları normal çalışır, ancak bir uyarıyla: JNI genel başvurusu GC kökü olarak değerlendirilir. Sonuç olarak, Bir Android çalışma zamanı VM nesnesi üzerinde tutan bir JNI genel başvurusu varsa, nesne koleksiyon için uygun olmasa bile toplanamaz .
Mono koleksiyonlar eğlencenin gerçekleştiği yerdir. Yönetilen nesneler normal şekilde toplanır. Eş nesneler aşağıdaki işlem gerçekleştirilerek toplanır:
Mono koleksiyonu için uygun tüm Eş nesneleri JNI genel başvurusu JNI zayıf genel başvurusu ile değiştirildi.
Android çalışma zamanı VM GC'si çağrılır. Herhangi bir Yerel eş örnek toplanabilir.
(1) içinde oluşturulan JNI zayıf genel başvuruları denetlendi. Zayıf başvuru toplandıysa Eş nesnesi toplanır. Zayıf başvuru toplanmadıysa, zayıf başvuru bir JNI genel başvurusu ile değiştirilir ve Eş nesnesi toplanmaz. Not: API 14+ üzerinde bu, döndürülen değerin GC'den
IJavaObject.Handle
sonra değişebileceği anlamına gelir.
Tüm bunların sonucu, bir Peer nesnesinin bir örneğinin yönetilen kod (örneğin bir static
değişkende depolanan) veya Java kodu tarafından başvurulacağı sürece yaşayacağıdır. Ayrıca, Yerel eşlerin yaşam süresi, hem Yerel eş hem de Yönetilen eş toplanabilir olana kadar Yerel eş toplanabilir olmayacağından, aksi takdirde yaşayacakları sürenin ötesine uzatılır.
Nesne Döngüleri
Eş nesneler hem Android çalışma zamanında hem de Mono VM'lerde mantıksal olarak bulunur. Örneğin, Android.App.Activity yönetilen eş örneğine karşılık gelen bir android.app.Activity framework eş Java örneği olacaktır. Java.Lang.Object dosyasından devralan tüm nesnelerin her iki VM'de de gösterimleri olması beklenebilir.
Her iki VM'de de temsili olan tüm nesnelerin ömrü, yalnızca tek bir VM içinde (örneğin) System.Collections.Generic.List<int>
bulunan nesnelerle karşılaştırıldığında uzatılır.
GC çağrılır . Xamarin.Android GC'nin toplamadan önce nesneye herhangi bir VM tarafından başvurulmadığından emin olması gerektiğinden Toplama işlemi bu nesneleri toplamaz.
Nesne ömrünü kısaltmak için Java.Lang.Object.Dispose() çağrılmalıdır. Bu işlem, genel başvuruyu serbest kaldırarak iki VM arasındaki nesne üzerindeki bağlantıyı el ile "kesecek" ve böylece nesnelerin daha hızlı toplanmasına olanak tanır.
Otomatik Koleksiyonlar
Sürüm 4.1.0'da başlayan Xamarin.Android, gref eşiği aşıldığında otomatik olarak tam GC gerçekleştirir. Bu eşik, platform için bilinen maksimum greflerin %90'ını oluşturur: öykünücüde 1800 gref (maksimum 2000) ve donanımda 46800 gref (en fazla 52000). Not: Xamarin.Android yalnızca Android.Runtime.JNIEnv tarafından oluşturulan grefs'leri sayar ve işlemde oluşturulan diğer grefleri bilmez. Bu sadece buluşsal bir şey.
Otomatik 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 uygun olmayan zamanlarda (örneğin, grafik işlemenin ortasında) gerçekleşebilir. Bu iletiyi görürseniz, başka bir yerde açık bir koleksiyon gerçekleştirmek veya eş 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 sunar. GC Köprüsü olarak adlandırılan Mono çöp toplayıcısının uzantısı olarak uygulanır.
GC Köprüsü, Mono çöp toplama sırasında çalışır ve Android çalışma zamanı yığınıyla hangi eş nesnelerin "canlılıklarına" ihtiyaç duyduğunu bulur. GC Köprüsü aşağıdaki adımları (sırayla) yaparak bu belirlemeyi yapar:
Ulaşılamayan eş nesnelerin mono başvuru grafiğini temsil ettikleri Java nesnelerine dönüştürebilirsiniz.
Java GC gerçekleştirme.
Hangi nesnelerin gerçekten ölü olduğunu doğrulayın.
Bu karmaşık işlem, alt sınıflarının Java.Lang.Object
herhangi bir nesneye serbestçe başvurmasını sağlayan işlemdir; Java nesnelerinin C# ile ilişkili olabileceği kısıtlamaları kaldırır. Bu karmaşıklık nedeniyle, köprü işlemi çok pahalı olabilir ve uygulamada fark edilebilir duraklamalara neden olabilir. Uygulamada önemli duraklamalar yaşanıyorsa aşağıdaki üç GC Köprüsü uygulamasından birini incelemeye değer:
Tarjan - Robert Tarjan'ın algoritması ve geriye dönük başvuru yayma temelinde GC Köprüsü'nün tamamen yeni bir tasarımı. Sanal iş yüklerimiz altında en iyi performansa sahip olmakla birlikte, deneysel kodun daha büyük bir payına da sahiptir.
Yeni - İkincil davranışın iki örneğini düzelten ancak çekirdek algoritmayı (Güçlü bir şekilde bağlı bileşenleri bulmak için Kosaraju algoritmasına göre) tutan özgün kodun önemli bir şekilde elden geçirilmesi.
Eski - Özgün uygulama (üçünün en kararlısı olarak kabul edilir). Bu, duraklatmalar kabul edilebilirse
GC_BRIDGE
uygulamanın kullanması gereken köprüdür.
Hangi GC Köprüsü'nün en iyi şekilde çalıştığını anlamanın tek yolu, bir uygulamada denemeler yapmak ve çıkışı analiz etmektir. Karşılaştırma için verileri toplamanın iki yolu vardır:
Günlüğü etkinleştirme - Her GC Köprüsü seçeneği için günlüğe kaydetmeyi etkinleştirin (Yapılandırma bölümünde açıklandığı gibi), ardından her ayardan günlük çıkışlarını yakalayıp karşılaştırın.
GC
Her seçenek için iletileri, özellikleGC_BRIDGE
de iletileri inceleyin. Etkileşimli olmayan uygulamalar için 150 metreye kadar duraklamalar tolere edilebilir, ancak çok etkileşimli uygulamalar (oyunlar gibi) için 60ms'nin üzerinde duraklamalar bir sorundur.Köprü muhasebesini etkinleştirme - Köprü muhasebesi, köprü işleminde yer alan her nesnenin işaret ettiği nesnelerin ortalama maliyetini görüntüler. Bu bilgilerin boyuta göre sıralanması, en fazla sayıda ek nesnenin ne olduğuna ilişkin ipuçları sağlar.
Varsayılan ayar Tarjan'dır. Bir regresyon bulursanız, bu seçeneği Eski olarak ayarlamanız gerekebilir. Ayrıca, Tarjan performansta bir iyileştirme üretmezse daha kararlı Eski seçeneğini kullanmayı seçebilirsiniz.
Bir uygulamanın hangi GC_BRIDGE
seçeneği kullanması gerektiğini belirtmek için, öğesini veya bridge-implementation=tarjan
ortam değişkenine MONO_GC_PARAMS
geçirinbridge-implementation=old
bridge-implementation=new
. Bu, projenize build eylemiyleAndroidEnvironment
yeni bir dosya ekleyerek gerçekleştirilir. Örneğin:
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 azaltmasına yardımcı olmanın birden çok yolu vardır.
Eş örneklerin atılması
GC, işlemin tamamlanmamış bir görünümüne sahiptir ve gc belleğin düşük olduğunu bilmediğinden bellek düşük olduğunda çalışmayabilir.
Örneğin, Java.Lang.Object türünün veya türetilmiş türün bir örneği en az 20 bayt boyutundadır (bildirimde bulunmadan değiştirilebilir vb.). Yönetilen Çağrılabilen Sarmalayıcılar ek örnek üyeleri eklemez, bu nedenle 10 MB bellek blobunu ifade eden bir Android.Graphics.Bitmap örneğinize sahip olduğunuzda, Xamarin.Android'in GC'sinin bunu bilmediğinden GC 20 baytlık bir nesne görür ve 10 MB belleği canlı tutan Android çalışma zamanı tarafından ayrılmış nesnelere bağlandığını belirleyemez.
GC'ye yardımcı olmak sık sık gereklidir. Ne yazık ki GC. AddMemoryPressure() ve GC. RemoveMemoryPressure() desteklenmez, bu nedenle java tarafından ayrılmış büyük bir nesne grafı serbest bırakıldığını biliyorsanız GC'yi el ile çağırmanız gerekebilir. Bir GC'den Java tarafı belleği serbest bırakmasını isteyen Collect() veya Java.Lang.Object alt sınıflarını açıkça atarak yönetilen çağrılabilen sarmalayıcı ile Java örneği arasındaki eşlemeyi bozabilirsiniz.
Not
Alt sınıf örneklerini atarken Java.Lang.Object
son derece dikkatli olmanız gerekir.
Bellek bozulması olasılığını en aza indirmek için çağrısı Dispose()
yaparken aşağıdaki yönergelere bakın.
Birden Çok İş Parçacığı Arasında Paylaşım
Java veya yönetilen örnek birden çok iş parçacığı arasında paylaşılabilirse, hiçbir zaman d olmamalıdırDispose()
. Örneğin Typeface.Create()
önbelleğe alınmış bir örnek döndürebilir. Birden çok iş parçacığı aynı bağımsız değişkenleri sağlarsa, aynı örneği alır. Sonuç olarak, Dispose()
örneğin bir iş parçacığından lanması Typeface
diğer iş parçacıklarını geçersiz kılabilir ve bu da örneğin başka bir iş parçacığından JNIEnv.CallVoidMethod()
atılması nedeniyle diğer iş parçacıklarından (diğerlerinin yanı) s'ye neden ArgumentException
olabilir.
Bağlı Java Türlerini Yok Etme
Örnek bağlı bir Java türündeyse, örnek yönetilen koddan yeniden kullanılamayacağı ve Java örneğinin iş parçacıkları arasında paylaşılmayacağı sürece örnek atılabilir (önceki Typeface.Create()
tartışmaya bakın). (Bu belirlemeyi yapmak zor olabilir.) Java örneği yönetilen koda bir sonraki girişinde, bunun için yeni bir sarmalayıcı oluşturulur.
Bu, Drawables ve diğer yoğun kaynak örnekleri söz konusu olduğunda sık sık yararlıdır:
using (var d = Drawable.CreateFromPath ("path/to/filename"))
imageView.SetImageDrawable (d);
Yukarıdaki güvenlidir çünkü Drawable.CreateFromPath() tarafından döndürülen Eş, Kullanıcı eşlerine değil Bir Çerçeve eşine başvurur. Dispose()
Bloğun using
sonundaki çağrı, yönetilen Drawable ve framework Drawable örnekleri arasındaki ilişkiyi keserek Java örneğinin Android çalışma zamanının gerek duyduğu anda toplanmasına olanak tanır. Eş örneği bir Kullanıcı eşine başvuruda bulunursa bu güvenli olmaz; burada kullanıcı eşlerine başvuramadığını ve bu nedenle çağrının Drawable
Dispose()
güvenli olduğunu bilmek için "dış" bilgileri kullanıyoruz.
Diğer Türleri Yok Etme
Örnek, Java türünün bağlaması olmayan bir türe başvuruyorsa (özel gibi), hiçbir Java kodunun bu örnekte geçersiz kılınan yöntemleri çağırmayacağını bilmiyorsanızÇAĞıRMAYINDispose()
.Activity
Bunun yapılmaması, s ile sonuçlanmamasına NotSupportedException
neden olur.
Örneğin, özel tıklama dinleyiciniz varsa:
partial class MyClickListener : Java.Lang.Object, View.IOnClickListener {
// ...
}
Java gelecekte üzerinde yöntemler çağırmaya çalışacağından bu örneği atmamalısınız:
// BAD CODE; DO NOT USE
Button b = FindViewById<Button> (Resource.Id.myButton);
using (var listener = new MyClickListener ())
b.SetOnClickListener (listener);
Özel Durumları Önlemek için Açık Denetimler Kullanma
Java.Lang.Object.Dispose aşırı yükleme yöntemi uyguladıysanız JNI içeren nesnelere dokunmaktan kaçının. Bunu yapmak, kodunuzun zaten çöp olarak toplanmış temel alınan bir Java nesnesine erişmeyi (önemli ölçüde) denemesini mümkün kılan bir çift atma durumu oluşturabilir. Bunun yapılması 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 sonra bu null üyede sonraki bir erişim girişimi bir özel durumun oluşmasına neden olduğunda oluşur. Özellikle, nesnenin Handle
(yönetilen örneği temel alınan Java örneğine bağlayan) ilk atmada geçersiz kılınmıştır, ancak yönetilen kod artık kullanılamasa bile bu temel Java örneğine erişmeye çalışır (Java örnekleri ile yönetilen örnekler arasındaki eşleme hakkında daha fazla bilgi için bkz . Yönetilen Çağrılabilen Sarmalayıcılar ).
Bu özel durumu önlemenin iyi bir yolu, yönteminizde Dispose
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 deyişle, üyelerine erişmeden önce nesnenin Handle
null (IntPtr.Zero
) olup olmadığını denetleyin. Örneğin, aşağıdaki Dispose
yöntem bir childViews
nesneye erişir:
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 atma geçişi geçersiz for
Handle
bir geçişe neden olursachildViews
, döngü erişimi bir ArgumentException
oluşturur. İlk childViews
erişimden önce açık Handle
bir null denetimi ekleyerek, aşağıdaki Dispose
yöntem özel durumun oluşması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şvurulacak Örnekleri Azaltma
GC sırasında bir Java.Lang.Object
tür veya alt sınıfın örneği her taransa, örneğin başvurduğu nesne grafiğinin tamamı da taranmalıdır. Nesne grafı, "kök örneğinin" başvurduğu nesne örnekleri kümesidir ve ayrıca kök örneğin başvurduğu her şey özyinelemeli olarak kullanılır.
Aşağıdaki sınıfı göz önünde bulundurun:
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)));
}
}
BadActivity
Nesne grafı oluşturulduğunda, 10004 örnek (1x , 1x strings
BadActivity
, tarafından tutulan strings
1x string[]
, 10000x dize örnekleri) içerir ve bunların tümü her örnek tarandığında BadActivity
taranmalıdır.
Bunun koleksiyon sürelerinizi olumsuz etkileyerek GC duraklatma sürelerinin artmasına neden olabilir.
Kullanıcı eş örnekleri tarafından köklenen nesne grafiklerinin boyutunu küçülterek GC'ye yardımcı olabilirsiniz. Yukarıdaki örnekte bu işlem Java.Lang.Object dosyasından devralınmayan ayrı bir sınıfa geçirilerek BadActivity.strings
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
İkincil koleksiyonlar GC çağrılarak el ile gerçekleştirilebilir. Topla(0). Küçük koleksiyonlar ucuz (büyük koleksiyonlarla karşılaştırıldığında) ancak önemli bir sabit maliyeti vardır, bu nedenle bunları çok sık tetiklemeniz gerekmez ve birkaç milisaniyelik bir duraklatma süresine sahip olmanız gerekir.
Uygulamanızın aynı şeyin tekrar tekrar yapıldığı bir "görev döngüsü" varsa, görev döngüsü sona erdikten sonra küçük bir koleksiyonu el ile gerçekleştirmeniz önerilir. Örnek görev döngüleri şunlardır:
- Tek bir oyun çerçevesinin işleme döngüsü.
- Belirli bir uygulama iletişim kutusuyla tüm etkileşim (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 GC.Collect(GC.MaxGeneration)
.
Bunlar nadiren gerçekleştirilmelidir ve 512 MB yığını toplarken Android stili bir cihazda saniyelik bir duraklatma süresine sahip olabilir.
Ana koleksiyonlar yalnızca el ile çağrılmalıdır( varsa):
Uzun görev döngülerinin sonunda ve uzun bir duraklama kullanıcıya sorun sunmaz.
Geçersiz kılınan bir Android.App.Activity.OnLowMemory() yöntemi içinde.
Tanılama
Genel başvuruların ne zaman oluşturulup yok edildiğini izlemek için, debug.mono.log sistem özelliğini gref ve/veya gc içerecek şekilde ayarlayabilirsiniz.
Yapılandırma
Xamarin.Android çöp toplayıcısı ortam değişkeni ayarlanarak MONO_GC_PARAMS
yapılandırılabilir. Ortam değişkenleri, AndroidEnvironment Derleme eylemiyle ayarlanabilir.
Ortam MONO_GC_PARAMS
değişkeni, aşağıdaki parametrelerin virgülle ayrılmış bir listesidir:
nursery-size
= boyut : Çocuk odasının boyutunu ayarlar. Boyut bayt cinsinden belirtilir ve iki üssü olmalıdır. ve soneklerik
m
g
sırasıyla kilo, mega ve gigabaytları belirtmek için kullanılabilir. Kreş birinci nesildir (iki nesil). Daha büyük bir kreş genellikle programı hızlandırır ancak açıkçası daha fazla bellek kullanacaktır. Varsayılan kreş boyutu 512 kb.soft-heap-limit
= boyut : Uygulama 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ştirilir. Bu sınırın üzerinde GC, bellek kullanımı (daha fazla koleksiyon) için iyileştirilmiştir.evacuation-threshold
= eşik : Tahliye eşiğini yüzde olarak ayarlar. Değer, 0 ile 100 arasında bir tamsayı olmalıdır. Varsayılan değer 66'dır. Koleksiyonun süpürme aşaması belirli bir yığın bloğu türünün doluluk oranının 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 olacak şekilde geri yüklenir. 0 değeri tahliyeyi kapatır.bridge-implementation
= köprü uygulaması : Bu, GC performans sorunlarını gidermeye 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 ilk çöp haline geldikten sonra bir GC toplanmasına neden olabilecek bir iyileştirme içerir. Bu seçenek dahil olmak bu iyileştirmeyi devre dışı bırakır ve GC'leri daha öngörülebilir ancak potansiyel olarak daha yavaş hale getirir.
Örneğin, GC'yi 128 MB yığın boyutu sınırına sahip olacak şekilde yapılandırmak için, içeriğiyle birlikte Derleme eylemiyleAndroidEnvironment
Projenize yeni bir dosya ekleyin:
MONO_GC_PARAMS=soft-heap-limit=128m