Monodroid viewpager内存不足

时间:2013-10-28 12:10:28

标签: android memory-leaks android-viewpager xamarin.android

我正在尝试缩小内存问题,并创建了一个带有两个选项卡的ViewPager,每个选项卡包含以编程方式创建的5000个按钮。没有静态引用,所以我很困惑为什么按钮不会被清除。

按下第二个按钮后,我得到一个OutOfMemory错误,MAT告诉我我有19,416个引用“android.widget.Button”,其中class_references选项卡告诉我其中19,416个是java.lang.ref.WeakReference。我只希望有大约10,000,因为我在启动包含ViewPager的活动之前调用了GC.Collect()。

我上传了converted hprof file

这是我的代码:

MainActivity:

        button.Click += delegate {
            GC.Collect();

            StartActivity(typeof(MyPagerActivity));
        };

MyPagerActivity:

public class MyPagerActivity : Activity
{
    private MyPagerAdapter m_pageradapter;
    private ViewPager m_viewpager;

    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (null); // Always recreate everything (parameter is null)

        RequestWindowFeature(WindowFeatures.ActionBar);
        SetContentView(Resource.Layout.tabactivity);

        InitialiseTabs();
    }

    void InitTab (Fragment frag, string sTitle)
    {
        ActionBar.Tab tab = ActionBar.NewTab();
        m_pageradapter.AddFragment(frag);
        tab.SetText (sTitle);
        tab.TabSelected += HandleTabSelected;
        ActionBar.AddTab(tab);
    }

    void InitialiseTabs()
    {
        m_pageradapter = new MyPagerAdapter(FragmentManager);
        View v = FindViewById(Resource.Id.viewpager);
        m_viewpager = v.JavaCast<ViewPager>();

        InitTab(new FragLotsOfButtons (), "Buttons 1");
        InitTab(new FragLotsOfButtons (), "Buttons 2");

        ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;

        m_viewpager.PageSelected += HandlePageSwipe;
        m_viewpager.Adapter = m_pageradapter;
    }

    void HandlePageSwipe (object sender, ViewPager.PageSelectedEventArgs e)
    {
        ActionBar.SetSelectedNavigationItem(e.Position);
    }

    void HandleTabSelected (object sender, ActionBar.TabEventArgs e)
    {
        m_viewpager.CurrentItem = ActionBar.SelectedNavigationIndex;
    }
}

tabactivity.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <android.support.v4.view.ViewPager
        android:id="@+android:id/viewpager"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
</LinearLayout>

MyPagerAdapter:

class MyPagerAdapter : FragmentStatePagerAdapter
{
    private List<Fragment> m_frags;

    public MyPagerAdapter(FragmentManager fragman) : base(fragman)
    {
        m_frags = new List<Fragment>();
    }

    public void AddFragment(Fragment frag)
    {
        m_frags.Add(frag);
    }

    public override int GetItemPosition (Java.Lang.Object @object)
    {
        return FragmentStatePagerAdapter.PositionNone;
    }

    #region implemented abstract members of FragmentStatePagerAdapter
    public override Fragment GetItem (int p0)
    {
        return m_frags[p0];
    }
    #endregion
    #region implemented abstract members of PagerAdapter
    public override int Count {
        get {
            return m_frags.Count;
        }
    }
    #endregion
}

FragLotsOfButtons:

public class FragLotsOfButtons : Fragment
{
    private LinearLayout m_linearlayout = null;

    public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        m_linearlayout = new LinearLayout (Activity);
        m_linearlayout.LayoutParameters = new ViewGroup.LayoutParams (WindowManagerLayoutParams.FillParent, WindowManagerLayoutParams.FillParent);
        m_linearlayout.Orientation = Orientation.Vertical;

        AddButtons ();

        return m_linearlayout;
    }

    private void AddButtons ()
    {
        for (int i = 0; i < 2500; i++) {
            LinearLayout ll = new LinearLayout (Activity);
            ll.LayoutParameters = new ViewGroup.LayoutParams(WindowManagerLayoutParams.WrapContent, WindowManagerLayoutParams.WrapContent);
            ll.Orientation = Orientation.Horizontal;
            Button testview = new Button (Activity);
            testview.LayoutParameters = new ViewGroup.LayoutParams (WindowManagerLayoutParams.WrapContent, WindowManagerLayoutParams.WrapContent);
            testview.Text = "A" + i.ToString ();
            ll.AddView (testview);
            testview = new Button (Activity);
            testview.LayoutParameters = new ViewGroup.LayoutParams (WindowManagerLayoutParams.WrapContent, WindowManagerLayoutParams.WrapContent);
            testview.Text = "B" + i.ToString ();
            ll.AddView (testview);
            m_linearlayout.AddView (ll);
        }
    }
}

到目前为止,我已经在StackOverflow上尝试了一些解决方案而且没有任何乐趣。

修改

添加了异常信息:

Instance    {Java.Lang.OutOfMemoryError: Exception of type 'Java.Lang.OutOfMemoryError' was thrown.
    at Android.Runtime.JNIEnv.CallVoidMethod (intptr,intptr,Android.Runtime.JValue[]) [0x00023] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.8.2-branch/a25a31d0/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.g.cs:368
        at Android.Views.ViewGroup.AddView (Android.Views.View) [0x00043] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.8.2-branch/a25a31d0/source/monodroid/src/Mono.Android/platforms/android-15/src/generated/Android.Views.ViewGroup.cs:1357
            at PagerAdapterTest.FragLotsOfButtons.AddButtons () [0x000a5] in c:\Users\David.Wright\Documents\Projects\PagerAdapterTest\PagerAdapterTest\FragLotsOfButtons.cs:44
            at PagerAdapterTest.FragLotsOfButtons.OnCreateView (Android.Views.LayoutInflater,Android.Views.ViewGroup,Android.OS.Bundle) [0x00032] in c:\Users\David.Wright\Documents\Projects\PagerAdapterTest\PagerAdapterTest\FragLotsOfButtons.cs:25
            at Android.App.Fragment.n_OnCreateView_Landroid_view_LayoutInflater_Landroid_view_ViewGroup_Landroid_os_Bundle_ (intptr,intptr,intptr,intptr,intptr) [0x00022] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.8.2-branch/a25a31d0/source/monodroid/src/Mono.Android/platforms/android-15/src/generated/Android.App.Fragment.cs:990
            at (wrapper dynamic-method) object.f5d8ab18-1268-411a-908a-67c8e30f2dce (intptr,intptr,intptr,intptr,intptr) <IL 0x00023, 0x0005f>

            --- End of managed exception stack trace ---
            java.lang.OutOfMemoryError
            at android.view.ViewGroup.addInArray(ViewGroup.java:3735)
            at android.view.ViewGroup.addViewInner(ViewGroup.java:3694)
            at android.view.ViewGroup.addView(ViewGroup.java:3543)
            at android.view.ViewGroup.addView(ViewGroup.java:3488)
            at android.view.ViewGroup.addView(ViewGroup.java:3464)
            at pageradaptertest.FragLotsOfButtons.n_onCreateView(Native Method)
            at pageradaptertest.FragLotsOfButtons.onCreateView(FragLotsOfButtons.java:28)
            at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:829)
            at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1035)
            at android.app.BackStackRecord.run(BackStackRecord.java:635)
            at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1399)
            at android.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:437)
            at android.support.v13.app.FragmentStatePagerAdapter.finishUpdate(FragmentStatePagerAdapter.java:167)
            at android.support.v4.view.ViewPager.populate(ViewPager.java:1064)
            at android.support.v4.view.ViewPager.populate(ViewPager.java:911)
            at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1432)
            at android.view.View.measure(View.java:15524)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5109)
            at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1396)
            at android.widget.LinearLayout.measureVertical(LinearLayout.java:681)
            at android.widget.LinearLayout.onMeasure(LinearLayout.java:574)
            at android.view.View.measure(View.java:15524)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5109)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
            at android.view.View.measure(View.java:15524)
            at android.widget.LinearLayout.measureVertical(LinearLayout.java:833)
            at android.widget.LinearLayout.onMeasure(LinearLayout.java:574)
            at android.view.View.measure(View.java:15524)
            at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5109)
            at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2397)
            at android.view.View.measure(View.java:15524)
            at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1986)
            at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1227)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1400)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1120)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4604)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
            at android.view.Choreographer.doCallbacks(Choreographer.java:555)
            at android.view.Choreographer.doFrame(Choreographer.java:525)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
            at android.os.Handler.handleCallback(Handler.java:615)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4921)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
            at dalvik.system.NativeStart.main(Native Method)
}   Java.Lang.OutOfMemoryError

LogCat说:

[dalvikvm-heap] Clamp target GC heap from 64.406MB to 64.000MB
[dalvikvm-heap] Clamp target GC heap from 65.822MB to 64.000MB
[dalvikvm-heap] Clamp target GC heap from 65.888MB to 64.000MB
[dalvikvm-heap] Clamp target GC heap from 65.888MB to 64.000MB
[dalvikvm-heap] Forcing collection of SoftReferences for 8800-byte allocation
[dalvikvm-heap] Clamp target GC heap from 65.888MB to 64.000MB
[dalvikvm-heap] Out of memory on a 8800-byte allocation.
[dalvikvm-heap] Clamp target GC heap from 65.889MB to 64.000MB
[dalvikvm-heap] Clamp target GC heap from 65.904MB to 64.000MB
[dalvikvm-heap] Clamp target GC heap from 65.904MB to 64.000MB

1 个答案:

答案 0 :(得分:0)

当然你有10k Buttons,但你也在实例化LayoutParameters并将文本分配给Buttons,但你也将所有内容封装在LinearLayouts中。所有Java.Lang.Objects都是GREF参考文献。

我没有看到任何地方,你真正摆脱了你的Fragment实例,这些实例可能被你的Adapter所占据,直到它认为你不再需要它为止。因此,简单地调用GC.Collect()将无效。