4G / LTE上的Android HttpClient OOM(HTC Thunderbolt)

在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有更好的select吗?

  • 关于如何解决这个问题的任何想法? 我自己没有4G设备,我不能在模拟器中发生这种情况,所以我需要在这里进行一些有教育意义的猜测。 我可以尝试在我的代码中捕捉OOM并尝试清理并强制GC,但我不确定这是否是一个好主意。 意见或其他build议?

以下是我的代码所做的事情:

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 = default 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.AbstractPooledC onnAdapter.open(AbstractPooledConnAdapter.java:119)I / dalvikvm(11639):at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348)I / dalvikvm(11639):at org.apache。 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):额外信息:足迹= 24327KB,允许的足迹= 24519KB,修剪= 348KB W / dalvikvm(11639 ):threadid = 9:以未捕获的exception退出的线程(group = 0x40025b38)

Solutions Collecting From Web of "4G / LTE上的Android HttpClient OOM(HTC Thunderbolt)"

看着堆栈跟踪,看起来像Android的HttpClient.execute()实现是抛出一个OOM。

这不是由你在这个问题上的堆栈跟踪指示的。 当然,你没有提供关于这个问题的整个堆栈跟踪。

获得Android开发者关注的最好方法是什么? 比报告http://code.google.com/p/android/issues有更好的select吗&#xFF1F;

这是一个纯粹的Android错误的可能性很小,但不是零。

这里有一些其他的可能性,没有特别的顺序:

  1. execute()本身没有问题,但是你只是内存不足,而且你遇到的堆栈跟踪只是简单地说明execute()正在强调你的堆。

  2. 问题在于HTC对于Thunderbolt对Android做了一些修改,可能只在LTEnetworking上生效。

  3. 这个问题在某种程度上是由Verizon LTEnetworking本身造成的(例如,他们的一些代理发送了造成HttpClient连接的螺旋球信息)。

关于如何解决这个问题的任何想法?

首先,我会使用现有的工具(例如,倾销HPROF并使用Eclipse MAT进行检查)来​​确认您没有内存泄漏,一般Thunderbolt / LTE组合似乎正在跳闸。

接下来,我build议您想出一些方法来始终如一地重现错误。 这可能是您现有的应用程序需要遵循一系列的步骤,或者它可能是一个专门的应用程序(例如,logging触发OOM的URL,然后创build一个小应用程序,只是做HttpClient请求)。 我希望DeviceAnywhere有一个Thunderbolt,但它看起来不像。 我会安排一些触angular,看看我能否在这方面得到一些帮助。

在解决这个问题上,作为一个权宜之计,你可以通过android.os.Build数据检测到你正在Thunderbolt上运行,也许你是通过ConnectivityManager在LTE上(我猜LTE将被列为WiMAX ,但这只是一个猜测),并警告用户有关该组合的问题。

除此之外,你可以尝试改变你的HttpClient的使用,看看它是否有效果,如:

  • 如果您只支持API Level 8或更高版本,则可以给AndroidHttpClient一个AndroidHttpClient替代品
  • 禁用multithreading访问(通常或Thunderbolt特定)并摆脱ThreadSafeClientConnManager

对不起,我在这里没有“魔术弹道”的答案。


UPDATE

现在我已经有了完整的堆栈跟踪,通过源代码查看…照亮了一些。

问题似乎是这样的:

 HttpConnectionParams.getSocketBufferSize(params); 

正在返回2MB左右的触发OOM的值。 这是一个非常大的缓冲区,特别是对于Dalvik GC引擎,它可能会被分割(是的,再次有这个词)。

这里的paramsHttpParams 。 你似乎通过getHttpParams()来创build自己的。 例如, AndroidHttpClient将其设置为8192:

 HttpConnectionParams.setSocketBufferSize(params, 8192); 

如果您自己设置套接字缓冲区大小,请尝试减小它。 如果没有,尝试将其设置为8192,看看是否有帮助。

这是修复: https : //review.source.android.com/22852

同时,URLConnection是免疫的。 只有HttpClient有这个问题。

如果你是一个想要testing这种失败的开发者,你可以使用“adb shell setprop”来设置,例如“net.tcp.buffersize.wifi”,这样当你的设备在wifi上。 像下面这样的东西将是一个真正的压力testing:

 adb shell setprop net.tcp.buffersize.wifi 4096,80999999,80999999,4096,80999999,80999999 

正是这种configuration改变,演习了HttpClient的bug。 我不知道Thunderbolt上的确切值是什么,但有人用设备可以find使用“adbshellgetprop | grep buffersize”。

也许这将有助于:

 // 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);