简体   繁体   中英

on iOS/iPhone: “Too many open files”: need to list open files (like lsof)

We've discovered our complex iPhone app (ObjC, C++, JavaScript/WebKit) is leaking file descriptors under unusual circumstances.

I need to know which files (by file path) we are leaving open.

I want something like the BSD command "lsof", which, of course, isn't available in iOS 4, at least not to me. Ideally a C or ObjC function. Or a tool, like shark or Instruments. Just need the files for our running app, not (as with lsof) for all apps/processes.

We do all sorts of things with files, and the code that is failing with "Too many open files" hasn't changed in ages, and since the circumstances are unusual, this could have crept in months ago. So there's no need to remind me to look at code that opens files and make sure I close them. I know that already. Would be nice to narrow it down with something lsof-esque. Thanks.

#import <sys/types.h>  
#import <fcntl.h>
#import <errno.h>
#import <sys/param.h>

+(void) lsof
{
    int flags;
    int fd;
    char buf[MAXPATHLEN+1] ;
    int n = 1 ;

    for (fd = 0; fd < (int) FD_SETSIZE; fd++) {
        errno = 0;
        flags = fcntl(fd, F_GETFD, 0);
        if (flags == -1 && errno) {
            if (errno != EBADF) {
                return ;
            }
            else
                continue;
        }
        fcntl(fd , F_GETPATH, buf ) ; 
        NSLog( @"File Descriptor %d number %d in use for: %s",fd,n , buf ) ;
        ++n ; 
    }
}

For future reference, I ran into a similar problem on an iPhone 11 with iOS 13; I was creating too many file descriptors (FDs) by creating too many files and sockets. My solution was to increase FDs at runtime with setrlimit() .

First I got the FD limits on my iPhone 11, with the following code:

// This goes somewhere in your code
struct rlimit rlim;

if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
    std::cout << "Soft limit: " << rlim.rlim_cur << std::endl;
    std::cout << "Hard limit: " << rlim.rlim_max << std::endl;
} else {
    std::cout << "Unable to get file descriptor limits" << std::endl;
}

After running getrlimit() , I could confirm that on iOS 13, the soft limit is 256 FDs, and the hard limit is infinite FDs. Since I was creating > 300 FDs between files and sockets, my app was crashing.

In my case I couldn't decrease the number of FDs, so I decided to increase the FD soft limit instead, with this code:

// This goes somewhere in your code
struct rlimit rlim;

rlim.rlim_cur = NEW_SOFT_LIMIT;
rlim.rlim_max = NEW_HARD_LIMIT;

if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) {
    std::cout << "Unable to set file descriptor limits" << std::endl;
}

NOTE: You can find more information on gettrlimit() and setrlimit() here and here .

Can you reproduce the problem running in the simulator?

If so, then you could actually use "lsof"...


update:

Ok, if you can't use the simulator, then idea #2:

When you get the "too many open files" error, call a function that iterates through all open file descriptors and dumps some information about each (for example the length and the first few bytes).

难道你不能用你自己的函数拦截所有打开的文件,比如my_fopen ,并将描述符和它们的名字一起存储,这样当你打开太多文件时,你可以查看你的列表来查看所有描述符是什么?

If Instruments isn't working well for your purposes, my next recommendation would be to run your app in the simulator, and use fs_usage on the command line to track the file descriptors you're opening and closing. Something like this:

  1. In Terminal, run "sudo fs_usage -f filesys MyAppName", replacing MyAppName with the name of your app.
  2. Launch your app.
  3. Look at the file descriptor open and close commands output by fs_usage to see which files you're leaving open.

Instruments.app might be able to help you (/Developer/Applications/Instruments.app). Run your app using the System Usage tool in Instruments, and it'll probably show you what you need to know. Best of all, it can be used while running the app on your device, without jailbreaking it.

I suggest you run your app on a jailbroken iPhone, and use Backgrounder and MobileTerminal to take a look at the files currently open.

You can get an iPhone binary of lsof here: http://modmyi.com/cydia/package.php?id=6945

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM