我有一个android客户端,可通过REST风格的端点和JSON与服务器进行通信。因此,我需要先检索完整的服务器响应,然后再将其转换为哈希。我有以下代码可以做到这一点(可以在某个地方的互联网上找到):
private static String convertStreamToString(InputStream is) { BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String line = null; try { while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } } catch (IOException e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } return sb.toString(); }
该代码在大多数情况下有效,但是我在行中看到OutOfMemory异常的客户端发生崩溃的报告:
while ((line = reader.readLine()) != null) {
完整的堆栈跟踪为:
java.lang.RuntimeException: An error occured while executing doInBackground() at android.os.AsyncTask$3.done(AsyncTask.java:200) at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) at java.util.concurrent.FutureTask.setException(FutureTask.java:124) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307) at java.util.concurrent.FutureTask.run(FutureTask.java:137) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561) at java.lang.Thread.run(Thread.java:1102) Caused by: java.lang.OutOfMemoryError at java.lang.String.(String.java:468) at java.lang.AbstractStringBuilder.toString(AbstractStringBuilder.java:659) at java.lang.StringBuilder.toString(StringBuilder.java:664) at java.io.BufferedReader.readLine(BufferedReader.java:448) at com.appspot.myapp.util.RestClient.convertStreamToString(RestClient.java:303) at com.appspot.myapp.util.RestClient.executeRequest(RestClient.java:281) at com.appspot.myapp.util.RestClient.Execute(RestClient.java:178) at com.appspot.myapp.$LoadProfilesTask.doInBackground(GridViewActivity.java:1178) at com.appspot.myapp.$LoadProfilesTask.doInBackground(GridViewActivity.java:1) at android.os.AsyncTask$2.call(AsyncTask.java:185) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) ... 4 more
我的问题:除了从服务器发送较小的数据块外,还有什么方法可以解决此问题?
谢谢!
通常,答案是否定的,但是您当然可以调整导致内存不足的条件。特别是,如果您在流之前发送字符串长度,则将能够创建一个内部具有正确数组大小的StringBuilder。创建后无法调整数组的大小,因此,如果StringBuilder中的数组容量用完,则实现必须分配一个新数组(通常为两倍大小,以避免过多的调整大小),然后复制旧数组内容。考虑大小为X的流,要调整刚好是X-1容量的StringBuilder的大小,则需要近X * 3的内存量。调整StringBuilder的大小,从而避免调整大小,这将使您可以将较大的流压缩到内存中。
您可能想做的另一件事是调整服务器进程可用的内存量。启动服务器进程时,请使用-Xmx1024m之类的开关。
当然,最好修改算法以不要求将整个流都保存在内存中。它使您能够使用相同数量的硬件处理更多的客户端。