Volley内存溢出问题V1.1.0:请求队列创建引发OOM异常求助
解决Volley中的OutOfMemoryError(pthread_create失败)问题
看起来你遇到的是Volley创建线程时触发的内存溢出问题,这个pthread_create (1040KB stack) failed的异常通常是因为系统中线程数量过多,内存资源被耗尽导致的。结合你的代码和异常信息,我来给你分析下核心原因和对应的解决方案:
核心原因分析
你的代码里虽然做了reQuestQue == null的判断,但可能存在以下问题:
- RequestQueue单例实现不严谨,导致重复创建多个RequestQueue实例,每个实例都会初始化一组线程池,最终线程数量爆炸
- 没有使用Application Context,导致RequestQueue持有Activity/Fragment的上下文,引发内存泄漏,累积占用内存
- 如果请求的响应数据过大,Volley默认会把整个响应加载到内存中,也可能触发OOM(不过你的异常是线程创建失败,这个是次要但需要排查的点)
解决方案
1. 严格实现RequestQueue的单例模式
确保整个App中只有一个RequestQueue实例,避免重复创建线程池。推荐使用双重检查锁的单例,并绑定Application Context:
public class VolleySingleton { private static VolleySingleton sInstance; private RequestQueue mRequestQueue; private static Context sCtx; private VolleySingleton(Context context) { sCtx = context.getApplicationContext(); // 用Application Context避免内存泄漏 mRequestQueue = getRequestQueue(); } public static synchronized VolleySingleton getInstance(Context context) { if (sInstance == null) { sInstance = new VolleySingleton(context); } return sInstance; } public RequestQueue getRequestQueue() { if (mRequestQueue == null) { // 这里可以自定义线程池大小,减少默认的线程数 mRequestQueue = Volley.newRequestQueue(sCtx, new HurlStack(), 2); } return mRequestQueue; } }
使用方式:
VolleySingleton.getInstance(mContext).getRequestQueue().add(mGsonRequest);
2. 减少Volley的网络线程池大小
Volley默认的网络线程池大小是4(NETWORK_THREAD_POOL_SIZE),如果你的App不需要同时处理大量请求,可以手动降低这个数值,减少线程占用的内存:
// 创建RequestQueue时指定线程数为2 RequestQueue requestQueue = new RequestQueue( new DiskBasedCache(mContext.getCacheDir()), new BasicNetwork(new HurlStack()), 2 ); requestQueue.start();
3. 取消无用请求,避免内存泄漏
在Activity/Fragment销毁时,取消所有关联的未完成请求,防止请求持有上下文导致内存泄漏:
// 添加请求时设置唯一tag mGsonRequest.setTag("MY_ACTIVITY_REQUESTS"); VolleySingleton.getInstance(mContext).getRequestQueue().add(mGsonRequest); // 在Activity的onDestroy方法中取消 @Override protected void onDestroy() { super.onDestroy(); VolleySingleton.getInstance(this) .getRequestQueue() .cancelAll("MY_ACTIVITY_REQUESTS"); }
4. 处理大响应数据(如果存在)
如果你的请求返回的数据量很大,Volley默认会把整个响应加载到内存中,这也可能引发OOM。此时可以使用StreamingRequest来分块读取响应:
public class LargeResponseRequest extends Request<byte[]> { private final Listener<byte[]> mListener; public LargeResponseRequest(int method, String url, Listener<byte[]> listener, ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; } @Override protected Response<byte[]> parseNetworkResponse(NetworkResponse response) { // 直接返回原始字节数组,避免Volley默认的字符串转换(大字符串会占用更多内存) return Response.success(response.data, HttpHeaderParser.parseCacheHeaders(response)); } @Override protected void deliverResponse(byte[] response) { mListener.onResponse(response); } @Override public Priority getPriority() { return Priority.LOW; // 降低大请求的优先级,减少对其他请求的影响 } }
总结
先从单例模式的正确性入手排查,这是引发线程数量过多的最常见原因;然后检查线程池大小、请求取消逻辑,最后再确认是否有大响应数据的问题。按照这个顺序排查,应该能解决你遇到的OOM问题。
内容的提问来源于stack exchange,提问作者Chinthaka Devinda
相关产品推荐
相关产品推荐

