Android报错too many open files

今天在开发时,出现了这个错误,然后软件闪退了,其实以前也出现过,只不过没有上心,这次正好让老板看到这个问题,所以必须要想办法解决了。。。
看报错,说是打开了太多的文件(其实不准确,只是我一开始是这么以为的),然后就从这方面开始入手去找问题,巧的是正好那个地方确实有打开文件,所以我一开始以为就是这个原因导致的。
这里我是请求接口,然后展示相关数据,再去对各条数据进行其他处理,这里会展示多张图片,因为这些图片是基本固定的,所以我就把这些图片缓存在了本地,节省用户的流量,然后就是每次展示图片都会去读取这些图片,找到读取图片相关的代码:

	FileInputStream fs = null;
	try {
    	fs = new FileInputStream(goodsImages  + "/" + dataListBean.getGoodsId() + ".jpg");
    	Bitmap bitmap  = BitmapFactory.decodeStream(fs);
    	holder.iv_icon.setImageBitmap(bitmap);
    } catch (IOException e) {
    	e.printStackTrace();
    	Log.e("MedicineListAdapter", "图片读取错误" + e.getLocalizedMessage());
    }

发现这里确实是只打开了流,没有把它关闭,所以在这里读取完之后,加一个关闭流:

	FileInputStream fs = null;
	try {
		fs = new FileInputStream(goodsImages  + "/" + dataListBean.getGoodsId() + ".jpg");
		Bitmap bitmap  = BitmapFactory.decodeStream(fs);
		//在这里加一个关闭
		fs.close();
		holder.iv_icon.setImageBitmap(bitmap);
	} catch (IOException e) {
		e.printStackTrace();
		Log.e("MedicineListAdapter", "图片读取错误" + e.getLocalizedMessage());
	}

但是加完之后,发现还是不行,还是那个错误,还是会闪退,又因为我这里会往日志文件里边写日志,所以我又怀疑是不是因为我写日志的时候打开了日志文件,然后导致的呢?
于是去看了写日志的代码,没有发现有什么问题,我就把写日志那里给注释掉了,来确实是不是他的问题,发现注释掉之后,还是一样的错误,那就肯定不是这里的问题了啊,但是我别的也没有什么打开文件的操作了啊,于是我一点一点的去注释代码,一步一步的排除,最后确定到了一段代码,就是添加物品那里。
这里呢就是调用接口来将所选择的这个物品告诉到服务端,也就是会一遍一遍的去掉同一个接口,而问题又是因为大量的点击才会出现,所以基本确定问题就在这里了,难道是因为开的线程太多了?但是我当时在写的时候就是害怕开的线程太多,所以在这里使用的是线程池,而且是固定大小的线程池啊,空闲线程应该是被回收的啊,所以我很纳闷。
但是又测试了几次,发现确实是这里的问题,于是开始修改这里:

public static final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(8);

这是创建线程池。
使用:

fixedThreadPool.submit(new ThreadInfo());
    private class ThreadInfo implements Runnable{
        //在run方法里写具体的操作
        @Override
        public void run() {
            try {
                OkHttpClient client = new OkHttpClient();
                StringBuilder sb = new StringBuilder(baseUrl+"/xxxx/xxx");
                sb.append("/").append("xxxx"); 
                Request request = new Request.Builder()
                        .url(sb.toString())
                        .get()
                        .build();
                client.newCall(request).enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        Looper.prepare();
                        ToastUtil.showTextToast(context,"请求数据数据失败:" + e.getMessage(),2500);
                        Looper.loop();
                    }
                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        String responseData = response.body().string();
                        Log.e("ThreadInfo",responseData);
                        Gson gson = new Gson();
                        CommonBean bean = gson.fromJson(responseData,CommonBean.class);
                        if(bean.getStatus != 200){
                        	Looper.prepare();
                        	ToastUtil.showTextToast(context,bean.getMessage,2500);
                        	Looper.loop();
                        }
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
                Looper.prepare();
                ToastUtil.showTextToast(context,"请求数据数据失败:" + e.getMessage(),2500);
                Looper.loop();
            }
        }
    }

我把请求的改了一下:

    private class ThreadInfo implements Runnable{
        //在run方法里写具体的操作
        @Override
        public void run() {
            Log.e("ThreadInfo","请求过了");
        }
    }

再运行,发现无论请求多少次,都不会报错,所以其实我的线程池是可以回收线程的,那么问题就出在了这个请求接口上边,我合理的猜测是因为这个接口的问题,于是我从网上找了一个第三方的接口,也就是那种一天调无数次的大公司给出来的官方的接口,发现还是有这个问题,所以,猜测是请求的问题,而不是接口的问题,于是再次搜索,发现有人说OKhttpclient实例在空闲一分钟之后才会回收销毁,所以可能就是因为这个原因。
于是打开studio的Profiler观察,发现调用这个接口之后,确实线程数是在不断的增加的,并没有减少,在一分钟之后,才会开始一点点的减少,所以猜测,确实是这个问题:
在这里插入图片描述
可以看到这里有六百多个线程,后边的基本都是okhttp产生的,所以可以确定,问题就是这个了。
但是这个请求,在String responseData = response.body().string();之后应该就会自动关闭了啊。。。
查询可知,是因为我这里每次调用这个接口,都会产生一个新的client的实例,而他在一分钟之后才会被回收,如果请求速度太快的,就会导致程序崩溃了,问题发现了,那么解决的思路就有了,一是要减少创建实例,二是想办法修改回收时间,于是这里就改成了:

OkHttpClient client = new OkHttpClient().newBuilder().connectionPool(new ConnectionPool(50,10, TimeUnit.SECONDS)).build();

全局创建一个实例,在他的连接池里允许最大是存在50个线程,线程空闲5秒之后就会被回收,这样应该就没问题了吧。
但是,修改完之后还是有很多线程,也并没有按照我想的那样空闲5秒之后就回收,而是一直在sleep,于是,再找原因,发现是looper的问题,looper.loop并不是就把开的这个关闭了,所以他就一直在这里死循环着,导致线程回收不掉,但是在这里,我又没有办法去弹出来一个吐司,于是用handler来进行处理了:

Message message = Message.obtain();
message.what = 1;
message.obj = medicineBuyBean.getMessage();
handler.sendMessage(message);
    @SuppressLint("HandlerLeak")
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 1:
                    ToastUtil.showTextToast(context,(String)msg.obj,2500);
                    break;
            }
        }
    };

再试,发现不论点击多快,点击多少次,线程都会稳定维持在一个大概的数字,除非真的是请求的速度远远超过了回收的速度:
在这里插入图片描述
这个就是改完之后的程序运行的线程,基本都维持在这么一个水准。

写下来就是因为自己费了很大的劲才算是勉强解决了这个问题(当然,可能大家解决这个问题要比我快得多),上边应该是有很多地方有错误或者是表达不准确,欢迎大家帮忙指出来。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这个错误通常是因为系统打开的文件句柄数已经达到了上限。可以通过以下命令查看系统当前打开的文件句柄数限制: ``` ulimit -n ``` 如果显示的数字比较小,可以通过以下命令增加限制: ``` ulimit -n 65536 ``` 这里的数字可以根据实际需要进行调整。如果还是出现该错误,可以尝试优化代码中文件打开和关闭的方式,尽量减少文件句柄的使用。 ### 回答2: Vue报错"too many open files, open"是由于打开文件的数量超过了系统所允许的限制。操作系统为每个进程设定了文件描述符的限制,当超过这个限制时,就会出现该报错。 要解决这个问题,可以采取以下步骤: 1. 检查代码中是否频繁地打开和关闭文件,或者打开文件的数量超过了需要的数量。如果是这种情况,可以优化代码,减少文件的打开和关闭次数,合理管理文件的使用。 2. 检查操作系统的文件描述符限制。可以使用命令`ulimit -n`来查看当前限制值,如果发现当前值太小,可以通过修改系统配置文件进行调整。 3. 检查代码中是否存在文件未正确关闭的情况。如果文件在使用后没有正确关闭,会导致文件描述符未释放,进而产生"too many open files"的错误。确保在使用完毕后,使用`close()`或者相关的关闭文件的方法将其关闭。 4. 考虑使用资源池或缓存来管理文件的打开和关闭操作。通过将文件的打开和关闭集中在池中进行管理,可以有效地减少文件描述符的使用数量。 总之,解决"too many open files, open"错误可以从优化代码,检查系统配置以及正确关闭文件等方面入手。提高代码的健壮性和资源的有效利用,可以避免这类问题的发生。 ### 回答3: "too many open files"是一个常见的错误信息,出现在使用Vue框架时。这个错误通常是由于操作系统限制导致的,表示同时打开的文件数量过多。 在操作系统中,每个进程都有一个最大打开文件描述符的限制。当程序尝试打开的文件数量超过这个限制时,就会出现"too many open files"错误。 在Vue中,这个错误通常与文件的引用或处理相关。可能是因为项目中同时打开了大量的文件,例如同时引入了过多的静态资源文件或同时打开了过多的文件流。 解决这个问题的方法有几种: 1. 修改操作系统的文件打开限制。可以通过调整操作系统配置,增加每个进程的最大打开文件描述符数量。具体的方法因操作系统而异,请根据使用的操作系统进行相关设置。 2. 优化Vue项目的资源引用。检查项目中的文件引入是否过多或冗余,尝试减少引入的文件数量。 3. 关闭不必要的文件流。在Vue代码中,确保正确关闭所有打开的文件流,避免文件流被过多打开而没有关闭的情况。 4. 使用合适的资源处理方式。在Vue开发中,可以考虑使用懒加载等方式减少同时处理的文件数量,以降低打开文件数量的压力。 总之,解决"too many open files"错误需要综合考虑操作系统配置、Vue项目的资源引用和文件流处理等因素。通过优化相关设置和代码,可以有效避免这个错误的发生。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值