У меня есть приложение, в котором есть пул потоков (ThreadPoolExecutor), которому передаются задачи, каждый из которых выполняет операцию HttpGet и считывает InputStream в байт [], чтобы что-то делать с.
После прочтения документов HttpClient я ушел с впечатлением, что лучший способ управлять соединениями HttpClient по нескольким потокам - это создать один ThreadSafeClientConnManager и поделиться им с приложением.
После реализации этого, я замечаю, что даже после завершения всех задач все еще сохраняется значительная часть памяти, которая используется ThreadSafeClientConnManager.
Глядя на кучу кучи, эта память находится в виде массивов byte []. Эти ссылки не поддерживаются никакими ссылками, которые я создал. Их держат куски ThreadSafeClientConnManager и его пул. Я не уверен, связаны ли они с InputStreams или если они что-то еще.
Все сами задачи и их переменные успешно собираются с мусором.
Если я вызываю getConnectionManager(). shutdown() в ThreadSafeClientConnManager, тогда вся память освобождается просто отлично. Тем не менее, я не хочу отключать соединение, потому что эти задачи HttpGet могут произойти в любое время. Я хотел бы оставить его открытым в течение продолжительности жизни приложений.
По мере запуска задач HttpGet сохраняемая память растет все больше и может в конечном итоге привести к ошибкам памяти. Когда задачи завершены, память не освобождается.
Как я могу обеспечить освобождение памяти после того, как закончившаяся задача завершилась?
Вот код, который я использую. Он скомпонован как можно лучше, чем код из документов HttpClient, другие вопросы здесь, на SO и в Интернете.
Создание HttpClient:
// Create and initialize HTTP parameters
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 40 * 1000);
HttpConnectionParams.setSoTimeout(params, 40 * 1000);
ConnManagerParams.setMaxTotalConnections(params, 100);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
// Create and initialize scheme registry
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register( new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
// Create an HttpClient with the ThreadSafeClientConnManager.
// This connection manager must be used if more than one thread will
// be using the HttpClient.
ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
mHttpClient = new DefaultHttpClient(cm, params);
Затем Runnable, который выполняет HttpGet, в значительной степени основан на примере из примеров HttpClient для Ручного подключения релиз. Вот пример того, как он выглядит:
HttpClient httpclient = getTheSharedThreadSafeClientConnManager(); // Would return the mHttpClient from above
try {
HttpGet httpget = new HttpGet("http://www.apache.org/");
// Execute HTTP request
System.out.println("executing request " + httpget.getURI());
HttpResponse response = httpclient.execute(httpget);
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
System.out.println("----------------------------------------");
// Get hold of the response entity
HttpEntity entity = response.getEntity();
// If the response does not enclose an entity, there is no need
// to bother about connection release
if (entity != null) {
InputStream instream = entity.getContent();
try {
instream.read();
// do something useful with the response
} catch (IOException ex) {
// In case of an IOException the connection will be released
// back to the connection manager automatically
throw ex;
} catch (RuntimeException ex) {
// In case of an unexpected exception you may want to abort
// the HTTP request in order to shut down the underlying
// connection immediately.
httpget.abort();
throw ex;
} finally {
// Closing the input stream will trigger connection release
try { instream.close(); } catch (Exception ignore) {}
}
}
}
Вам нужно еще сделать, чтобы освободить ресурсы для каждой задачи? Я видел в их примере ThreadSafeClientConnManager они использовали HttpContext, но я не могу найти документацию о том, как его использовать. Это необходимо? Если да, то как вы используете его с ThreadPoolExecutor?
Большое спасибо.