打开文件失败返回EMFILE的问题分析

打开文件失败返回EMFILE的问题分析

查找官网错误代码

在官网中查找到返回值为24对应的错误信息为EMFILE,对应的描述信息为EMFILE Too many open files 24,对应的中文翻译就是打开的文件太多.具体参考网址为:https://msdn.microsoft.com/en-us/library/t3ayayh1.aspx,对应的中文参考网址为:https://msdn.microsoft.com/zh-cn/magazine/t3ayayh1.aspx.由于是第一次碰到这种问题,且每次调用后我在析构函数中都调用了close,难道是fclose没有将FILE*关闭.windows系统存在这么明显的bug?显然是不可能的.
使用其它打开文件命令无法查看到返回错误信息的情况下可以通过上面的_wfopen_s来看看具体的错误值.
##调试fclose##
通过debug单步跟踪发现如下的调用关系:

  1. fclose
  2. _fclose_nolock
  3. _close(_fileno(stream))
    其中可以看到_fileno中获取的是stream中的_file,也就是文件no.具体FILE*的结构体如下:
struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;//文件句柄
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
        };

通过调试这里发现此处文件很明显是关闭了的.

伟大的_fcloseall()

通过查找发现有个NB的函数可以关掉所有的句柄,直接在释放位置调用该方法_fcloseall(),再进行测试,此时长时间运行都未出现问题.可惜由于应用的需要不能使用该方法,故可以肯定是在某个位置出现了句柄的内存泄漏.

输出发现大玄机

通过在fclose前面输出FILE* fp的fp->_file信息,通过测试发现该值不断增大当增大到512左右的时候,程序就出现了文件再也无法打开的情况.按道理windows系统中除了标准输入、标准输出和错误输出后_file不应该出现无限增加的情况,初步推断windows一个进程最多可以支持打开512个文件(未验证,据说linux的是1024,按道理这应该是可以配置的系统参数).

后续

通过追踪肯定是句柄问题后,通过逐步排查最终找到了文件未关闭的位置.

你可能感兴趣的:(MFC)