Moja aplikacja gromadzi wiele instancji, które nie mogą zostać odebrane przez GC. Ten wyciek pamięci powoduje awarię aplikacji na dłuższą metę.Dlaczego moje wątki nie umierają i nie powodują wycieku pamięci?
Nie jestem 100% pewien, skąd pochodzą, ale mam wrażenie, następujące potęgę być kod w pytaniu:
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);
}
}
Ten kod pozwala mi uruchomić kilka HTTP połączenia równoległe, które nie będą blokować się nawzajem na domyślnej AsyncTask
(która jest tylko pojedynczą kolejką wątków).
Sprawdziłem, czy AsyncTask
s faktycznie osiągają swoje metody onPostExecute()
i nie działają po prostu na zawsze. Po sprawdzeniu niektórych zrzutów pamięci podejrzewam, że opakowanie nie przestaje działać po zakończeniu AsyncTask
s.
Czy to możliwe, że powyższy kod jest nadal odpowiedzialny za wyciek pamięci, czy powinienem zacząć szukać gdzie indziej?
Każda pomoc jest doceniana.
Edytuj: Należy zauważyć, że sendRequest
jest tylko raz wywoływana. Inne części kodu, które nie znajdują się w powyższym przykładzie, zapewniają to.
Edit 2: super klasy wygląda następująco:
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 wygląda następująco:
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.");
}
}
Nie bardzo wiadomo, ale może to pomóc? http://www.androiddesignpatterns.com/2013/04/activitys-threads-memory-leaks.html – dumazy
Coś w konstruktorach super-klas AbstractUraHostConnection, które mogą być przerażające? Jak wygląda wygląd ConnectionTask? – ddmps
Dodano kod obu klas. – Chris