2013-04-25 9 views
5

私のアプリには、GCが取り上げて消去できない多くのThreadインスタンスが蓄積されています。このメモリリークは、長期的にはアプリケーションをクラッシュさせます。スレッドが死んでメモリリークの原因にならないのはなぜですか?

私は、彼らがどこから来た100%わからないんだけど、私は次のようを感じて明確なを持っている問題のコードのようになります。

public class UraHostHttpConnection extends AbstractUraHostConnection { 
    private Handler uiThreadHandler = new Handler(Looper.getMainLooper()); 
    private Executor taskExecutor = new Executor() { 
     public void execute(Runnable command) { 
      new Thread(command).start(); 
     } 
    }; 
    private ConnectionTask task = null; 

    @Override 
    public void sendRequest(final HttpUriRequest request) { 
     this.task = new ConnectionTask(); 
     this.uiThreadHandler.post(new Runnable() { 
      public void run() { 
       task.executeOnExecutor(taskExecutor, request); 
      } 
     }); 
    } 

    @Override 
    public void cancel() { 
     if (this.task != null) 
      this.task.cancel(true); 
    } 
} 

このコードは、私はHTTPいくつかを実行することができます並列接続で、デフォルトでAsyncTaskExecutor(これは単なるスレッド化されたキュー)でブロックされません。

AsyncTaskは、実際にはonPostExecute()の方法に達しており、永遠に実行されるだけではありません。いくつかのメモリダンプを調べた後、私はThread-AsyncTaskの完了後にオブジェクトが実行を停止しないと思う。

上記のコードでメモリリークが発生する可能性はありますか、それとも他の場所から探すべきですか?

何か助けていただければ幸いです。

編集:sendRequestは一度しか呼び出されません。上記のサンプルに含まれていないコードの他の部分は、それを確認します。

編集2:スーパークラスは次のようになります。あなたはオーバーコントロールを持つように

private class ConnectionTask extends AsyncTask<HttpUriRequest, Object, Void> { 
    final byte[] buffer = new byte[2048]; 
    private ByteArrayBuffer receivedDataBuffer = new ByteArrayBuffer(524288); 

    @Override 
    protected Void doInBackground(HttpUriRequest... arg0) { 
     UraHostHttpConnection.taskCounter++; 
     AndroidHttpClient httpClient = AndroidHttpClient.newInstance("IVU.realtime.app"); 
     try { 
      // Get response and notify listener 
      HttpResponse response = httpClient.execute(arg0[0]); 
      this.publishProgress(response); 

      // Check status code OK before proceeding 
      if (response.getStatusLine().getStatusCode() == 200) { 
       HttpEntity entity = response.getEntity(); 
       InputStream inputStream = entity.getContent(); 
       int readCount = 0; 

       // Read one kB of data and hand it over to the listener 
       while ((readCount = inputStream.read(buffer)) != -1 && !this.isCancelled()) { 
        this.receivedDataBuffer.append(buffer, 0, readCount); 
        if (this.receivedDataBuffer.length() >= 524288 - 2048) { 
         this.publishProgress(receivedDataBuffer.toByteArray()); 
         this.receivedDataBuffer.clear(); 
        } 
       } 

       if (this.isCancelled()) { 
        if (arg0[0] != null && !arg0[0].isAborted()) { 
         arg0[0].abort(); 
        } 
       } 
      } 
     } catch (IOException e) { 
      // forward any errors to listener 
      e.printStackTrace(); 
      this.publishProgress(e); 
     } finally { 
      if (httpClient != null) 
       httpClient.close(); 
     } 

     return null; 
    } 

    @Override 
    protected void onProgressUpdate(Object... payload) { 
     // forward response 
     if (payload[0] instanceof HttpResponse) 
      listener.onReceiveResponse((HttpResponse) payload[0]); 
     // forward error 
     else if (payload[0] instanceof Exception) 
      listener.onFailWithException((Exception) payload[0]); 
     // forward data 
     else if (payload[0] instanceof byte[]) 
      listener.onReceiveData((byte[]) payload[0]); 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
     listener.onReceiveData(this.receivedDataBuffer.toByteArray()); 
     listener.onFinishLoading(); 
     UraHostHttpConnection.taskCounter--; 
     Log.d(TAG, "There are " + UraHostHttpConnection.taskCounter + " running ConnectionTasks."); 
    } 
} 
+0

本当にわからないあなたのプールのX =サイズすることができますが、このヘルプあなたは? http://www.androiddesignpatterns.com/2013/04/activitys-threads-memory-leaks.html – dumazy

+1

Spookingする可能性のあるAbstractUraHostConnectionのスーパークラスのコンストラクタには何もありませんか?また、ConnectionTaskはどのように見えますか? – ddmps

+0

両方のクラスのコードが追加されました。 – Chris

答えて

1

置き換えあなたの執行のためのThreadPoolExecutor:

public abstract class AbstractUraHostConnection { 
    protected IUraHostConnectionListener listener = null; 

    public void setListener(IUraHostConnectionListener listener) { 
     this.listener = listener; 
    } 
    public abstract void sendRequest(HttpUriRequest request); 
    public abstract void cancel(); 
} 

AsyncTaskはこのようになりますプールのサイズ。 ThreadPoolExecutorが基本的に公開メソッドであるExecutorである場合、デフォルトの最大プールサイズが非常に高く設定されている場合があります。

公式文書here

で特に見てみましょう:あなたは、あなたが本当にしたいとどのくらいのコードをあなたはそれを得るためにトレードますどのくらいの制御に応じて、以下(より良いアイデアをコーディングしたい場合は、代替もあります

setCorePoolSize(int corePoolSize) 
//Sets the core number of threads. 

setKeepAliveTime(long time, TimeUnit unit) 
//Sets the time limit for which threads may remain idle before being terminated. 

setMaximumPoolSize(int maximumPoolSize) 
//Sets the maximum allowed number of threads. 

)。

Executor taskExecutor = Executors.newFixedThreadPool(x); 

どこ

+0

ありがとうございます。はい、それは問題を解決します。しかし、私のコードで何がうまくいかないのか不思議です。しばらくしてから応答のないスレッドを終了させることは、特にエレガントな解決策ではありません:-) – Chris

+1

代わりに編集されました。スレッド*は自動的にGCされるべきですが、われわれが知っているように、GCは、直接質問しても、GCが何をしているかを行います。私は根本的なメカニズムについてもっと知りたがっていますが、彼らは私に何もないKludgeと呼んでいません...また、プールを制限することで、あなた自身でゾンビを狩る必要がなくなります。 – MarsAtomic

関連する問題