在AsyncTask中启动内存时发生内存泄漏(从线程中更改)

问题描述:

我对Android开发很陌生,当我发现内存泄露很大时即将完成我的第一个应用程序。在AsyncTask中启动内存时发生内存泄漏(从线程中更改)

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的原因是因为我需要从一个缓慢而大的web服务中读取数据,这需要一些时间。我在活动中显示了一个加载栏,突出显示所选的项目,直到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线程概述堆转储之一(这是非常难以阅读,因为我不允许张贴HTML的链接和图像就像在MAT的副本因为我的用户级别...)。该线程的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 
+0

如果你正在调试,然后调试器“持有”到某些线程,所以你不一定会看到他们从调试器消失,即使他们已经完成。尝试只运行你的应用程序,并检查线程是否消失。看到这个问题的两个答案更多信息http://*.com/questions/3077461/asynctask-threads-never-die-android – 2011-05-17 14:34:20

+0

看来,线程还没有消失。我不知道HPROF转储是否显示已完成的线程,但我可以说应用程序内存缓慢变得越来越大,直到应用程序最终在负载下崩溃。这只发生在我使用线程或AsyncTasks时,但AsyncTasks花费更长时间使应用程序崩溃 – mrTanaka 2011-05-18 12:04:19

你应该看看AsyncTask,在那里你做负载在doInBackground()中,在onPreExecute中设置状态栏,使用publishProgess发布进度更新,然后删除onPostExecute中的进度栏​​。

+1

谢谢!我尝试了AsyncTask,它确实提高了性能。不幸的是,线程仍然留在堆中,但它们不再随着时间的推移而增长。不过,如果我能够让这些线程消失,这将是非常好的,我会尽快更新我的问题 – mrTanaka 2011-05-17 12:58:49

哦,我的背景中的一些工作完成后有一件特别的事情可以开始活动。 AsyncTask与ProgressDialog有界。看到一个example.

+0

谢谢!我尝试了AsyncTask,它确实提高了性能。不幸的是,线程仍然留在堆中,但它们不再随着时间的推移而增长。不过,如果我可以让这些线程消失,那将是非常好的,我很快就会更新我的问题 – mrTanaka 2011-05-17 12:58:39