2013-04-25 5 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 :는 슈퍼 클래스는 다음과 같습니다

AsyncTask를이 모양
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(); 
} 

: 있도록

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에 당신이 제어 할 수 있습니다 수영장의 크기. 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

관련 문제