为什么我的线程不会死机并导致内存泄漏?
我的一个应用程序积累了很多Thread
GC无法拾取和清除的实例。这种内存泄漏从长远来看会使应用程序崩溃。为什么我的线程不会死机并导致内存泄漏?
我不是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并行连接不会在默认的AsyncTask
Executor
(这只是一个单线程队列)上彼此阻塞。
我检查了一下,AsyncTask
s实际上是达到他们的onPostExecute()
方法,并且不只是永远运行。在检查了一些内存转储后,我怀疑包装Thread
-在AsyncTask
s完成后,对象不停止运行。
是否有可能上述代码仍然是我的内存泄漏的责任,或者我应该开始寻找其他地方?
任何帮助表示赞赏。
编辑:应该指出,sendRequest
只有一次被称为。代码的其他部分不在上面的示例中,以确保这一点。
编辑2:超一流看起来是这样的:
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看起来是这样的:
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.");
}
}
替换为您执行人的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);
其中x =您的池
谢谢。是的,这解决了这个问题。但出于好奇,我想知道我的代码出了什么问题。在一段时间后杀死没有响应的线程并不是一个特别优雅的解决方案:-) – Chris 2013-04-25 09:27:23
编辑替代选项的答案。线程*应该自动GCed,但正如我们所知,GC甚至在我们直接询问时也会做GC的工作。我希望我对底层机制有更多的了解,但是他们不会把我称为Kludge ......另外,限制游泳池不应该让你自己追捕僵尸。 – MarsAtomic 2013-04-25 09:29:48
不能确定的大小,但能这样帮助你吗? http://www.androiddesignpatterns.com/2013/04/activitys-threads-memory-leaks.html – dumazy 2013-04-25 09:00:03
AbstractUraHostConnection的超类的构造函数中的任何内容可能会令人惊讶?另外ConnectionTask看起来如何? – ddmps 2013-04-25 09:03:47
添加了这两个类的代码。 – Chris 2013-04-25 09:09:29