【问题标题】:Memory leaks when starting Activity in AsyncTask (changed from Thread)在 AsyncTask 中启动 Activity 时内存泄漏(从 Thread 更改)
【发布时间】:2011-05-17 11:47:19
【问题描述】:

我对 Android 开发还很陌生,当我注意到我有一个巨大的内存泄漏时,我正要完成我的第一个应用程序。

当我从一个线程中启动一个新活动时,就会发生泄漏:

private static class CatalogRowOnClickListener implements OnClickListener 
{
    List<CatalogRow> catRows;
    WeakReference<CatalogViewActivity> mActivity;

    CatalogRowOnClickListener(WeakReference<CatalogViewActivity> mActivity) 
    {
        this.mActivity = mActivity;
        catRows = new ArrayList<CatalogRow>();
    }


    public void addCatalogRow(CatalogRow row) 
    {
        catRows.add(row);
    }

    public void onClick(View v) 
    {   
        v.setBackgroundColor(Color.argb(150, 255, 255, 255));


        final ProgressBar linProgressBar = (ProgressBar) v.findViewById(R.id.CatProgressBar);
        linProgressBar.setVisibility(View.VISIBLE);

        final View fv = v;
        final fItem fhitem = findFItem(fv);
        try
        {
            new Thread()
            {


                public void run() 
                {
                    initializeApp();

                }
                public void initializeApp()
                {
                    // Initialize application data here


                    FItemListStore.getItemsFromWebservice(fhitem);
                    boolean isArticleOverview = false;

                    for(FItem item: FItemListStore.fItemViewStorage) 
                    {   
                        if( item instanceof fiArticle ) 
                        {
                            isArticleOverview = true;
                            break;
                        }
                    }


                    Intent intent = new Intent();
                    intent.setClassName("nl.project.Android", "nl.project.Android.Activities.HomeViewActivity");
                    Bundle bundle = new Bundle();

                    if(isArticleOverview)
                    {
                        bundle.putInt("OverviewNr", 1);
                    }
                    else
                    {
                        bundle.putInt("OverviewNr", 0);
                    }
                    intent.putExtras(bundle);

                    //if( mActivity.get() != null )
                        mActivity.get().startActivity(intent);

                    mActivity.clear();

                }
            }.start();
        }
        catch (Exception e) {}

        //Debug.stopMethodTracing();
        //android.os.Debug.stopMethodTracing();
    }     

执行此代码后应用程序的 HPROF 转储显示线程将始终保留在堆中并呈指数增长。研究这一点指向引用导致泄漏的线程内的上下文。所以我把这段代码改了几次,直到变成这个版本,在静态类中只有一个弱引用(这是其他帖子中提到的一些事情)

之所以要在一个线程中启动Activity,是因为我需要从一个又慢又大的webservice中读取数据,这需要一些时间。我在活动中显示了一个加载栏,突出显示所选项目,直到完成XMLparser,然后开始一个新活动。

可能没有正确的方法在线程中启动活动而不会导致内存泄漏?而且,如果是这样,在 xml 解析器完成工作后,我是否还有其他方法可以启动意图?


在 Vladimir 和 Heiko 的建议下,我将线程更改为 AnyncTask。我的保留堆的增长已停止,但我启动的 AsyncTask 线程仍保留在堆中。这是我的新代码:

private static class QueryFHTask extends AsyncTask<FredHopperItem, Integer, Boolean> 
 {

     WeakReference<CatalogViewActivity> mActivity;

     QueryFHTask(WeakReference<CatalogViewActivity> mActivity) 
     {
        this.mActivity = mActivity;

     }


     protected void onPreExecute() 
     {

     }
     protected Boolean doInBackground(FItem... items) {
         int count = items.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             FItemListStore.getItemsFromWebservice(items[i]);
             boolean isArticleOverview = false;

             for(FItem item: FItemListStore.fhItemViewStorage) 
             {  
                if( item instanceof FArticle ) 
                {
                    isArticleOverview = true;
                    break;
                }
             }

             Intent intent = new Intent();
             intent.setClassName("nl.project.Android", "nl.project.Android.Activities.HomeViewActivity");
             Bundle bundle = new Bundle();

             if(isArticleOverview)
             {
                bundle.putInt("OverviewNr", 1);
             }
             else
             {
                bundle.putInt("OverviewNr", 0);
             }
             intent.putExtras(bundle);
             mActivity.get().startActivity(intent);

         }
         return true;
     }

     protected void onProgressUpdate(Integer... progress) {
         //setProgressPercent(progress[0]);

     }

     protected void onPostExecute(Long result) {
         //showDialog("Downloaded " + result + " bytes");
     }
 }

private static class CatalogRowOnClickListener implements OnClickListener 
{
    List<CatalogRow> catRows;
    WeakReference<CatalogViewActivity> mActivity;

    CatalogRowOnClickListener(WeakReference<CatalogViewActivity> mActivity) 
    {
        this.mActivity = mActivity;
        catRows = new ArrayList<CatalogRow>();
    }


    public void addCatalogRow(CatalogRow row) 
    {
        catRows.add(row);
    }

    public void onClick(View v) 
    {   
        v.setBackgroundColor(Color.argb(150, 255, 255, 255));
        final ProgressBar linProgressBar = (ProgressBar) v.findViewById(R.id.CatProgressBar);
        linProgressBar.setVisibility(View.VISIBLE);

        final View fv = v;
        final fItem fhitem = findFItem(fv);     
        new QueryFHTask(mActivity).execute(fhitem);       


    }

为了澄清我的问题,这是我的 HPROF 线程概述堆转储之一的副本(很难阅读,因为由于我的用户级别,我不允许在 MAT 中发布带有链接和图像的 html...) . AsyncTask 线程保留 376 或 344 的堆。随着我浏览应用程序的时间越长,来自AsyncActivity 线程的保留堆将越来越多...

Name Instance Shallow Heap Retained Heap Context Class Loader 
main java.lang.Thread @ 0x40027550 80 1.464 dalvik.system.PathClassLoader @ 0x4051ce30 
JDWP java.lang.Thread @ 0x40515838 80 384  
AsyncTask #6 java.lang.Thread @ 0x406ea788 80 376 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #7 java.lang.Thread @ 0x40690178 80 376 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #4 java.lang.Thread @ 0x4068a630 80 376 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #3 java.lang.Thread @ 0x406851f0 80 376 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #5 java.lang.Thread @ 0x405d9f28 80 376 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #2 java.lang.Thread @ 0x40539db0 80 376 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #1 java.lang.Thread @ 0x40517180 80 376 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #8 java.lang.Thread @ 0x4068cdb0 80 344 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #9 java.lang.Thread @ 0x4068b558 80 344 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #10 java.lang.Thread @ 0x4068a178 80 344 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #11 java.lang.Thread @ 0x406639f0 80 344 dalvik.system.PathClassLoader @ 0x4051ce30 
AsyncTask #12 java.lang.Thread @ 0x40661b00 80 344 dalvik.system.PathClassLoader @ 0x4051ce30 
Binder Thread #2 java.lang.Thread @ 0x40519b20 80 344  
Binder Thread #1 java.lang.Thread @ 0x40516868 80 344  
Thread-2 java.util.logging.LogManager$2$1 @ 0x40195298 80 168 dalvik.system.PathClassLoader @ 0x400277f8 
Signal Catcher java.lang.Thread @ 0x40515778 80 160  
Compiler java.lang.Thread @ 0x405158e8 80 152  
HeapWorker java.lang.Thread @ 0x40515618 80 152  
GC java.lang.Thread @ 0x405156d0 80 136  
Total: 21 entries  1.680 7.656 

【问题讨论】:

  • 如果您正在调试,那么调试器会“保留”某些线程,因此即使它们完成后您也不一定会看到它们从调试器中消失。尝试运行您的应用程序并检查线程是否消失。有关更多信息,请参阅此问题的两个答案stackoverflow.com/questions/3077461/…
  • 看来线程还没有消失。我不知道 HPROF 转储是否显示已经完成的线程,但我可以说应用程序内存慢慢变得越来越大,直到应用程序最终在负载下崩溃。这只发生在我使用线程或 AsyncTasks 时,但 AsyncTasks 需要更长的时间才能使应用程序崩溃

标签: android multithreading android-activity android-context ui-thread


【解决方案1】:

哦,天哪,在后台的一些工作完成后开始一个活动是一件特别的事情。它是带有 ProgressDialog 有界的 AsyncTask。查看example.

【讨论】:

  • 谢谢!我尝试了 AsyncTask,它确实提高了性能。不幸的是,线程仍然留在堆中,但它们不再随着时间的推移而增长。不过,如果我能让这些线程消失就太好了,我会尽快更新我的问题
【解决方案2】:

您应该查看AsyncTask,在doInBackground() 中进行加载,在onPreExecute 中设置状态栏,使用publishProgess 发布进度更新,然后在onPostExecute 中删除进度栏。

【讨论】:

  • 谢谢!我尝试了 AsyncTask,它确实提高了性能。不幸的是,线程仍然留在堆中,但它们不再随着时间的推移而增长。不过,如果我能让这些线程消失,那就太好了,我会尽快更新我的问题
猜你喜欢
  • 1970-01-01
  • 2017-05-16
  • 1970-01-01
  • 2016-01-27
  • 1970-01-01
  • 1970-01-01
  • 2020-05-07
  • 2018-03-29
  • 1970-01-01
相关资源
最近更新 更多