Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 为什么赢了';我的线程不会死并导致内存泄漏吗?_Android_Multithreading_Android Asynctask_Executor - Fatal编程技术网

Android 为什么赢了';我的线程不会死并导致内存泄漏吗?

Android 为什么赢了';我的线程不会死并导致内存泄漏吗?,android,multithreading,android-asynctask,executor,Android,Multithreading,Android Asynctask,Executor,我的一个应用程序正在积累大量GC无法获取和清除的线程实例。从长远来看,内存泄漏会使应用程序崩溃 我不能100%确定它们来自哪里,但我有一种明显的感觉,下面可能是有问题的代码: public class UraHostHttpConnection extends AbstractUraHostConnection { private Handler uiThreadHandler = new Handler(Looper.getMainLooper()); private Exec

我的一个应用程序正在积累大量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()
方法,而不是永远运行。检查了一些内存转储后,我怀疑在
异步任务
完成后,包装
线程
-对象不会停止运行

是否有可能上面的代码仍然对我的内存泄漏负责,或者我应该开始寻找其他地方

感谢您的帮助

Edit:应该注意,
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();
}
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.");
    }
}
异步任务如下所示:

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.");
    }
}
私有类连接任务扩展异步任务{
最终字节[]缓冲区=新字节[2048];
private ByteArrayBuffer receivedDataBuffer=新ByteArrayBuffer(524288);
@凌驾
受保护的Void doInBackground(HttpUriRequest…arg0){
UraHostHttpConnection.taskCounter++;
AndroidHttpClient httpClient=AndroidHttpClient.newInstance(“IVU.realtime.app”);
试一试{
//获取响应并通知侦听器
HttpResponse response=httpClient.execute(arg0[0]);
这是出版进度(回应);
//继续之前,请检查状态代码“OK”
if(response.getStatusLine().getStatusCode()==200){
HttpEntity=response.getEntity();
InputStream InputStream=entity.getContent();
int readCount=0;
//读取一kB的数据并将其交给侦听器
而((readCount=inputStream.read(buffer))!=-1&&!this.isCancelled()){
this.receivedDataBuffer.append(缓冲区,0,读取计数);
if(this.receivedDataBuffer.length()>=524288-2048){
this.publishProgress(receivedDataBuffer.toByteArray());
this.receivedDataBuffer.clear();
}
}
if(this.isCancelled()){
如果(arg0[0]!=null&&!arg0[0].IsOrted()){
arg0[0]。中止();
}
}
}
}捕获(IOE异常){
//将任何错误转发给侦听器
e、 printStackTrace();
这是出版进度(e);
}最后{
if(httpClient!=null)
httpClient.close();
}
返回null;
}
@凌驾
受保护的void onProgressUpdate(对象…负载){
//正向响应
if(HttpResponse的有效负载[0]实例)
onReceiveResponse((HttpResponse)有效负载[0]);
//正向误差
else if(负载[0]实例异常)
onFailWithException((异常)有效负载[0]);
//转发数据
else if(字节[]的有效负载[0]实例)
onReceiveData((字节[])有效负载[0]);
}
@凌驾
受保护的void onPostExecute(void结果){
onReceiveData(this.receivedDataBuffer.toByteArray());
onfinishload();
UraHostHttpConnection.taskCounter--;
Log.d(标记“There are”+URAHOSHTTPConnection.taskCounter+“running ConnectionTasks”);
}
}

将ThreadPoolExecutor替换为您的Executor,以便您可以控制池的大小。如果ThreadPoolExecutor基本上是一个具有公开方法的执行器,那么可能只是默认最大池大小设置得非常高的情况

官方文件

请特别注意:

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.
如果你想少编写代码,还有一个选择(更好的主意取决于你真正想要多少控制权,以及你为了得到它而要交换多少代码)


其中x=池的大小

不是很确定,但这能帮助您吗?AbstractUraHostConnection的超类的构造函数中有什么可能会引起惊吓的东西吗?还有ConnectionTask看起来怎么样?添加了两个类的代码。谢谢。是的,这就解决了问题。但出于好奇,我想知道我的代码出了什么问题。在一段时间后杀死无响应线程并不是一个特别优雅的解决方案:-)答案为另一种选择而编辑。线程应该自动地进行GCed,但是我们知道,GC做GC做的事情,当它想做的时候,甚至当我们直接请求时。我希望我能了解更多的潜在机制,但他们不会无缘无故地叫我“混球”。。。此外,限制池应该可以让你不必自己追捕僵尸。