4G/LTE上的Android HttpOOM客户端(HTC Thunderbolt)

4G/LTE上的Android HttpOOM客户端(HTC Thunderbolt),android,httpclient,4g,htc-android,htc-thunderbolt,Android,Httpclient,4g,Htc Android,Htc Thunderbolt,我从用户那里得到了一些关于在Verizon的4G/LTE上使用我的应用程序时崩溃的报告 查看堆栈跟踪,看起来Android的HttpClient.execute()实现抛出了一个OOM。这仅在4G/LTE设备上发生,特别是HTC Thunderbolt,并且仅在4G/LTE上发生。WiFi、3G、UMTS都可以。在Sprint的WiMax 4G上也可以正常工作 两个问题: 要引起Android开发者的注意,最好的方法是什么?还有比报告更好的选择吗 有什么办法可以解决这个问题吗?我自己没有4G设

我从用户那里得到了一些关于在Verizon的4G/LTE上使用我的应用程序时崩溃的报告

查看堆栈跟踪,看起来Android的HttpClient.execute()实现抛出了一个OOM。这仅在4G/LTE设备上发生,特别是HTC Thunderbolt,并且仅在4G/LTE上发生。WiFi、3G、UMTS都可以。在Sprint的WiMax 4G上也可以正常工作

两个问题:

  • 要引起Android开发者的注意,最好的方法是什么?还有比报告更好的选择吗

  • 有什么办法可以解决这个问题吗?我自己没有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 );

    ...
HttpParams params=this.getHttpParams();//返回参数
ClientConnectionManager cm=新的ThreadSafeClientConnManager(参数,this.getHttpSchemeRegistry());
DefaultHttpClient httpClient=新的DefaultHttpClient(cm,参数);
HttpResponse响应=null;
请求=新的HttpGet(url);
试一试{
response=httpClient.execute(请求);//
查看堆栈跟踪,看起来Android的HttpClient.execute()实现抛出了一个OOM

您在问题上的堆栈跟踪没有指出这一点。当然,您没有提供问题的整个堆栈跟踪

要引起Android开发者的注意,最好的方法是什么?还有比报告更好的选择吗

这是一个纯粹的安卓bug的可能性很小,尽管不是零

以下是一些其他可能性,没有特定顺序:

  • execute()

  • 问题在于HTC对Android的Thunderbolt做了一些修改,可能只有在LTE网络上才生效

  • 这个问题不知何故是由Verizon LTE网络本身造成的(例如,他们的一些代理发回了导致HttpClient连接的古怪信息)

  • 有什么办法可以解决这个问题吗

    首先,我会使用现有的工具(例如,转储HPROF和使用EclipseMat进行检查)来确认您一般不会出现Thunderbolt/LTE组合似乎会遇到的内存泄漏

    接下来,我建议你想出一些方法来一致地重现错误。这可能是你现有的应用程序,需要遵循一系列步骤,也可能是一个专用的应用程序(例如,记录触发OOM的URL,然后创建一个只执行HttpClient请求的小应用程序).我希望任何地方都有雷电,但看起来不像。我会试探一下,看看能否在这方面得到一些帮助

    就解决这个问题而言,作为一种权宜之计,你可以通过
    android.os.Build
    数据检测到你在Thunderbolt上运行,或者通过
    ConnectivityManager
    检测到你在LTE上运行(我猜LTE会被列为WiMAX,但这只是一个猜测),并警告用户该组合存在的问题

    除此之外,您还可以尝试稍微提高HttpClient的使用率,看看是否有效果,例如:

    • 如果您只支持API级别8或更高,您可以给
      AndroidHttpClient
      一次机会作为替代品
    • 禁用多线程访问(一般或特定于Thunderbolt)并摆脱ThreadSafeClientConnManager
    很抱歉,我这里没有“魔弹”的答案


    更新

    现在我有了完整的堆栈跟踪,查看源代码是…有启发性的,有些

    问题似乎是:

    HttpConnectionParams.getSocketBufferSize(params);
    
    正在返回触发OOM的2MB左右的值。这是一个非常大的缓冲区,特别是对于Dalvik GC引擎,它可能会变得支离破碎(是的,这个词又出现了)

    params
    这是
    HttpParams
    。您似乎是通过
    getHttpParams()
    自己创建的。例如,
    AndroidHttpClient
    将其设置为8192:

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

    以下是修复方法:

    同时,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”来找到它。

    也许这会有所帮助:

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

    @Psychik:我根据进一步的研究更新了答案,它本身就是根据你修改的堆栈跟踪更新的。@Psychik:“顺便说一句,你能告诉我你在哪里找到这段代码吗?”--使用谷歌代码搜索()。在搜索栏中输入类名,在Package字段中输入
    android.git.kernel.org
    。这对于解决此类问题非常有效。好消息是,所有行号都与回购协议中的最新内容匹配,因此没有任何猜测。我只是从实际的崩溃点开始反向工作,试图找出缓冲区大小来自@Psychik:“看看为什么我可能在其他手机/连接类型上看不到”——好吧,这是奇怪的部分。假设