当我在Verizon的4G / LTE上使用我的应用程序时,我收到了一些崩溃用户的报告。
查看堆栈跟踪,看起来Android的HttpClient.execute()实现正在抛出一个OOM。这仅发生在4G / LTE设备上,特别是HTC Thunderbolt,并且仅在4G / LTE上。 WiFi,3G,UMTS都可以。也适用于Sprint的WiMax 4G工作正常。
两个问题:
关于Android开发者关注此问题的最佳方式是什么?比http://code.google.com/p/android/issues报告更好的选择吗?
关于我如何解决这个问题的任何想法?我自己没有4G设备,我无法在模拟器中实现这一点,所以我需要在这里做一些有根据的猜测。我可以尝试在我的代码中捕获OOM并尝试清理并强制GC,但我不确定这是不是一个好主意。评论或其他建议?
这是我的代码正在做的事情:
HttpParams params = this.getHttpParams(); // returns params
ClientConnectionManager cm = new ThreadSafeClientConnManager(params, this.getHttpSchemeRegistry() );
DefaultHttpClient httpClient = new DefaultHttpClient( cm, params );
HttpResponse response = null;
request = new HttpGet( url );
try {
response = httpClient.execute(request); // <-- OOM on 4G/LTE. OK otherwise
int statusCode = response.getStatusLine().getStatusCode();
Log.i("fetcher", "execute returned, http status " + statusCode );
...
这是崩溃的堆栈跟踪:
E / dalvikvm-heap(11639):内存不足 在2055696字节分配。 I / dalvikvm(11639):“Thread-16”prio = 5 tid = 9 RUNNABLE I / dalvikvm(11639):| group =“main”sCount = 0 dsCount = 0 s = N. obj = 0x48563070 self = 0x3c4340 I / dalvikvm(11639):| sysTid = 11682 nice = 0 sched = 0/0 cgrp =默认值 handle = 3948760 I / dalvikvm(11639):| schedstat =(208709711 74005130 214)
I / dalvikvm(11639):at org.apache.http.impl.io.AbstractSessionInputBuffer.init(AbstractSessionInputBuffer.java:~79) I / dalvikvm(11639):at org.apache.http.impl.io.SocketInputBuffer。(SocketInputBuffer.java:93) I / dalvikvm(11639):at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:83) I / dalvikvm(11639):at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:170) I / dalvikvm(11639):at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:106) I / dalvikvm(11639):at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:129) I / dalvikvm(11639):at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:173) I / dalvikvm(11639):at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) I / dalvikvm(11639):at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) I / dalvikvm(11639):at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348) I / dalvikvm(11639):at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) I / dalvikvm(11639):at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) I / dalvikvm(11639):at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465) I / dalvikvm(11639):at com.myapplication.Fetcher.trySourceFetch(Fetcher.java:205) I / dalvikvm(11639):at com.myapplication.Fetcher.run(Fetcher.java:298) I / dalvikvm(11639):at java.lang.Thread.run(Thread.java:1102) I / dalvikvm(11639):E / dalvikvm(11639): 内存不足:堆大小= 24171KB, 分配= 23142KB,位图大小= 59KB, 限制= 21884KB E / dalvikvm(11639):额外 info:Footprint = 24327KB,允许 足迹= 24519KB,修剪= 348KB W / dalvikvm(11639):threadid = 9:thread 离开未被捕获的例外 (组= 0x40025b38)
答案 0 :(得分:26)
查看堆栈跟踪,看起来Android的HttpClient.execute()实现正在抛出一个OOM。
您在此问题上的堆栈跟踪未指示。当然,你没有在这个问题上提供整个堆栈跟踪。
关于Android开发者关注此问题的最佳方式是什么?比http://code.google.com/p/android/issues报告更好的选择吗?
这是一个纯粹的Android bug的可能性很小,但不是零。
以下是其他一些可能性,没有特别的顺序:
execute()
本身没有问题,但是你只是内存耗尽,而你遇到的堆栈跟踪只是证明execute()
正在给你的堆压力。
问题在于HTC为Android制作了一些针对Thunderbolt的修改,可能只在LTE网络上生效。
这个问题在某种程度上是由Verizon LTE网络本身造成的(例如,他们的某些代理发回了导致HttpClient陷入困境的搞砸信息)。
关于如何解决这个问题的任何想法?
首先,我使用现有的工具(例如,转储HPROF并使用Eclipse MAT进行检查)来确认您通常没有内存泄漏,因为Thunderbolt / LTE组合似乎正在绊倒。
接下来,我建议您想出一些方法来始终如一地重现错误。这可能是您现有的应用程序,需要遵循一系列步骤,或者它可以是专用应用程序(例如,记录触发OOM的URL,然后创建一个只执行HttpClient请求的小应用程序)。我希望DeviceAnywhere有一个Thunderbolt,但它看起来不像。我会放一些触角,看看我是否能在这方面得到一些帮助。
就解决这个问题而言,作为权宜之计,您可以通过android.os.Build
数据检测到您在Thunderbolt上运行,也许您通过ConnectivityManager
检测到您在LTE上运行(我是我猜测LTE会列为WiMAX,但这只是猜测,并警告用户该组合的问题。
除此之外,您可以尝试稍微改变您的HttpClient使用情况,看看它是否有效果,例如:
AndroidHttpClient
作为免费替换ThreadSafeClientConnManager
对不起,我在这里没有“魔弹”答案。
<强>更新强>
现在我已经拥有完整的堆栈跟踪,查看源代码是......有点亮。
问题似乎是:
HttpConnectionParams.getSocketBufferSize(params);
返回触发OOM的2MB左右的值。这是一个非常大的缓冲区,特别是对于Dalvik GC引擎而言,它可能会变得支离破碎(是的,再次出现这个词)。
params
这里是HttpParams
。您似乎是通过getHttpParams()
自己创建的。例如,AndroidHttpClient
将其设置为8192:
HttpConnectionParams.setSocketBufferSize(params, 8192);
如果您自己设置套接字缓冲区大小,请尝试减少它。如果没有,请尝试将其设置为8192并查看是否有帮助。
答案 1 :(得分:4)
这是修复:https://review.source.android.com/22852
同时,URLConnection是免疫的。它只有HttpClient才有这个问题。
如果您是想要测试此类故障的开发人员,可以使用“adb shell setprop”设置,例如“net.tcp.buffersize.wifi”,以便最大读/写套接字缓冲区大小为当你的设备在wifi上时很大。像下面这样的东西将是一个真正的压力测试:
adb shell setprop net.tcp.buffersize.wifi 4096,80999999,80999999,4096,80999999,80999999
这种配置更改可以解决HttpClient错误。我不知道Thunderbolt上的确切值是什么,但有设备的人可能会发现使用“adb shell getprop | grep buffersize”。
答案 2 :(得分:3)
也许这会有所帮助:
// Set the timeout in milliseconds until a connection is established.
int timeoutConnection = 5000;
// Set the default socket timeout (SO_TIMEOUT)
// in milliseconds which is the timeout for waiting for data.
int timeoutSocket = 4000;
// set timeout parameters for HttpClient
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
HttpConnectionParams.setSocketBufferSize(httpParameters, 8192);//setting setSocketBufferSize
DefaultHttpClient httpClient = new DefaultHttpClient();
httpClient.setParams(httpParameters);