开发者

Monodroid GREF problem best practice?

I have the following test code (based on standard monodroid HelloWorld)

namespace TestGREF
{
    [Activity (Label = "TestGREF", MainLauncher = true)]
    public class Activity1 : Activity
    {
        int count = 1;      
        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);
            SetContentView (Resource.Layout.Main);
            Button button = FindViewById<Button> (Resource.Id.myButton);

            button.Click += delegate {
                button.Text = string.Format ("{0} clicks!", count++); 
                for(int i=0;i<10000;i++){
                    new Java.La开发者_开发技巧ng.Object(new System.IntPtr(i));
                    //...some stuff here. Instead of Java.Lang.Object may be
                    //something much more useful.
                }

                //If uncomment here, looks ok
                //GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            };
        }
    }
}

If I click the button 5-6 times, application crashes.

I know this happens because of global refences (GREF) limit (described here, "Unexpected NullReferenceExceptions" section). The question is: what to do with it? What is the best practice? If possible, with code example please

If uncomment GC.Collect() call, all seems working, but calling GC too often is too exspensive for performance. Another popular design is to put new statement put of loop, but it is not always possible cause of program logic.

Any more ideas?


You need to release all unmanaged objects when they no longer needed. All classes that inherits from Android.Runtime.IJavaObject also inherits IDisposable so you need to dispose them.

Here is part from my project

private Spinner _spType;
private ArrayAdapter _arrayAdapter;

protected override void OnCreate(Android.OS.Bundle savedInstanceState)
{
  base.OnCreate(savedInstanceState);
  _spType = FindViewById<Spinner>(Resource.Id.spinnerType);
  _arrayAdapter = new ArrayAdapter(this, Android.Resource.Layout.SimpleSpinnerItem, new[] {"1","2","3","4","5"});
  _spType.Adapter = _arrayAdapter;
}

public override void Finish()
{
    if (_spType != null)
        _spType.Dispose();
    if (_arrayAdapter != null)
        _arrayAdapter.Dispose();
    base.Finish();
}


for(int i=0;i<10000;i++){
    var obj = new Java.Lang.Object(new System.IntPtr(i));

    //...some stuff here. Instead of Java.Lang.Object may be
    //something much more useful.

    obj.Dispose(); //Deletes an object and GREF too. 
    //Cannot be used if object is still used in dalvik VM
}

If you cannot use Dispose() (for example, unmanaged object is a part of layout, which will be used by android lated, but not by C# code), use GC.Collect() wisely. GC.Collect() kills all the GREFs to variables, which are out of usage by Mono Environment and out of current scope.


Here is article about GC and memory management in monodroid. It can be helpful for you http://docs.xamarin.com/android/advanced_topics/garbage_collection

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜