当我尝试在Verizon的4G/LTE上使用我的应用程序时,我从用户那里得到了一些关于崩溃的报告。
查看堆栈跟踪,它看起来像是Android的HttpClient.execute()实现正在抛出一个OOM。这种情况只发生在4G/LTE设备上,特别是HTC,只有在4G/LTE上才会出现。WiFi,3G,UMTS都很好。在Sprint的WiMax 4G上也很好用。
两个问题:
,
下面是我的代码所做的:
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堆(11639):2055696字节分配的内存不足.I/dalvikvm(11639):"Thread-16“prio=5 tid=9 RUNNABLE I/dalvikvm(11639):group="main”main“sCount=0 dsCount=0 s=N obj=0x48563070 self=0x3c4340 I/dalvikvm(11639):self=0x3c4340=0/0 cgrp=default handle=3948760 I/dalvikvm(11639):x-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:(11639):在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(org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465) I/dalvikvm(11639):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):内存不足:堆Size=24171KB,Allocated=23142KB,Bitmap Size=59KB,Limit=21884KB E/dalvikvm(11639):额外信息: Footprint=24327KB,with Footprint=24519KB,Trimmed=348KB W/dalvikvm(11639):threadid=9:线程退出与未指明的异常(group=0x40025b38)
发布于 2011-03-18 22:09:56
查看堆栈跟踪,它看起来像是Android的HttpClient.execute()实现正在抛出一个OOM。
这不是由您对问题的堆栈跟踪所指示的。当然,您没有提供关于这个问题的整个堆栈跟踪。
有比在http://code.google.com/p/android/issues上报道更好的选择吗?
这是一个纯粹的Android错误的可能性很小,虽然不是零。
以下是其他一些可能性,不按特定顺序排列:
execute()在压力你的堆。关于我如何解决这个问题,
有什么想法吗?
首先,我会使用现有的工具(例如,转储HPROF和使用Eclipse MAT检查)来确认您一般不会有内存泄漏,Thunderbolt/LTE组合似乎只是被绊倒了。
接下来,我建议您想出一些方法来始终如一地重现错误。这可能是您现有的应用程序,需要遵循一系列步骤,也可以是一个专用的应用程序(例如,记录触发OOM的URL,然后创建一个只执行HttpClient请求的小应用程序)。我希望DeviceAnywhere有一个雷电,但它看起来不像。我去试探一下,看看能不能在这方面得到帮助。
作为一种权宜之计,你可以通过android.os.Build数据检测到你在雷电上运行,也许你是通过ConnectivityManager在LTE上运行(我猜LTE会被列为WiMAX,但这只是猜测),并警告用户使用这种组合的问题。
除此之外,您还可以尝试稍微改变一下HttpClient的使用,看看它是否有效果,例如:
如果您只支持API级别8或更高版本,则可以将replacement
AndroidHttpClient一次尝试,并摆脱ThreadSafeClientConnManager。
很抱歉我这里没有“魔法子弹”的答案。
更新
现在我已经有了完整的堆栈跟踪,在一定程度上查看了源代码is...illuminating。
问题似乎是:
HttpConnectionParams.getSocketBufferSize(params);返回触发OOM的2MB左右的值。这是一个非常大的缓冲区,特别是对于Dalvik GC引擎来说,它可以变得支离破碎(是的,还有这个词)。
params这里是HttpParams。您似乎是通过getHttpParams()自己创建的。例如,AndroidHttpClient将其设置为8192:
HttpConnectionParams.setSocketBufferSize(params, 8192);如果您自己正在设置套接字缓冲区大小,请尝试减小它。如果没有,请尝试将其设置为8192,看看这是否有帮助。
发布于 2011-05-14 01:18:30
以下是修复方法:https://review.source.android.com/22852
同时,URLConnection是免疫的。只有HttpClient才有这个问题。
如果您是一个想要测试这种失败的开发人员,您可以使用“亚行外壳设置支持”来设置"net.tcp.buffersize.wifi“,这样当设备使用wifi时,最大的读/写套接字缓冲区大小就会很大。下面这样的东西将是一个真正的压力测试:
adb shell setprop net.tcp.buffersize.wifi 4096,80999999,80999999,4096,80999999,80999999正是这种配置更改使用了HttpClient错误。我不知道Thunderbolt上的确切值是多少,但是有这个设备的人可以使用“亚行外壳getprop \ grep缓冲区大小”来找出答案。
发布于 2011-06-08 10:35:29
也许这会有帮助:
// 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);https://stackoverflow.com/questions/5358014
复制相似问题