2013-04-25 29 views
5

Bir uygulamam, GC'nin toplayamadığı ve temizleyemeyeceği birçok Thread örneğini biriktiriyor. Bu bellek sızıntısı uzun vadede uygulamayı kilitler.Konularım neden ölmeyecek ve bir bellek sızıntısına neden olmayacak?

Ben % 100 değilim emin geldikleri, ancak ayrı bir soru kodu olması aşağıdaki kudretini duygu var burada:

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); 
    } 
} 

Bu kod bana birkaç çalışmasını sağlar HTTP Paralel olan bağlantılar, varsayılan olarak AsyncTaskExecutor (ki bu sadece tek bir iş parçacığıdır).

Kontrol ettim, AsyncTask s aslında onPostExecute() yöntemlerine ulaşıyor ve sadece sonsuza kadar koşmuyorlar. Bazı bellek döküntüleri incelendikten sonra Thread -Objects, AsyncTask s tamamlandıktan sonra çalışmayı durdurmadığından şüpheleniyorum.

Yukarıdaki kodun bellek sızıntısından hala sorumlu muyum yoksa başka bir yere mi bakmaya başlamalıyım?

Herhangi bir yardım için teşekkür ederiz.

Düzeltme: Not: sendRequest yalnızca bir kez çağrılır. Yukarıdaki örnekte bulunmayan kodun diğer bölümleri bundan emin olur.

Düzenleme 2: süper sınıf şuna benzer:

AsyncTask şöyle
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(); 
} 

: böylece

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

Gerçekten emin değilim senin havuzun x = büyüklüğü, ama can bu konularda yardımcı olabilir? http://www.androiddesignpatterns.com/2013/04/activitys-threads-memory-leaks.html – dumazy

+1

AbstractUraHostConnection süper sınıflarının kurucularında şaka olabilecek bir şey var mı? Ayrıca ConnectionTask nasıl görünüyor? – ddmps

+0

Her iki sınıfın da kodu eklendi. – Chris

cevap

1

yerine kendi Executor için ThreadPoolExecutor Eğer üzerinde kontrole sahip Havuzun büyüklüğü. ThreadPoolExecutor temelde açık yöntemler ile bir Executor ise, yalnızca varsayılan maksimum havuz boyutunun çok yüksek olduğu bir durum olabilir.

Resmi belge here.

de özellikle bir göz atın: Eğer bağlı olarak daha az (daha iyi bir fikir kodlamak isterseniz alternatif de var

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. 

ne kadar kontrole gerçekten istemek ve bunu elde etmek için ticaret edeceğiz ne kadar kod).

Executor taskExecutor = Executors.newFixedThreadPool(x); 

nerede

+0

Teşekkürler. Evet, bu sorunu çözüyor. Ama meraktan dolayı kodumda neyin yanlış gittiğini merak ediyorum. Bir süre sonra tepkisiz konuları öldürmek, özellikle zarif bir çözüm değildir :-) – Chris

+1

Yanıt bir alternatif için düzenlenmiştir. Konular * otomatik * GCed olmalıdır, ancak bildiğimiz gibi, GC doğrudan istediğimiz zaman bile, GC'nin istediğini yapar.Keşke altta yatan mekanizma hakkında daha fazla şey bilmemi isterdim, ama bana Kludge diye bir şey demezler ... Ayrıca, havuzu sınırlamak, zombi avlamak zorunda kalmanızı engeller. – MarsAtomic

İlgili konular