当出现 Too many open files异常的时候,意味着文件句柄泄漏过多,句柄泄漏到一定数量之后(一般是接近1024)会导致程序卡死、文件读写异常、socket创建异常等。
一般来说单一进程的最大可打开文件句柄数量为1024,可通过cat proc/进程ID/limits查看。

image.png
java代码查询最大句柄数量
public static int getMaxOpenFiles() {
RandomAccessFile randomAccessFile = null;
try {
randomAccessFile = new RandomAccessFile("/proc/" + Process.myPid() + "/limits", "r");
String line;
while ((line = randomAccessFile.readLine()) != null) {
if (line.contains("Max open files")) {
line = line.replace("Max open files", "")
.replace("files", "").trim();
String[] split = line.split(" ");
for (String item : split) {
if (!TextUtils.isEmpty(item)) {
randomAccessFile.close();
randomAccessFile = null;
return Integer.parseInt(item);
}
}
}
}
} catch (Exception e) {
Log.w(TAG, e);
} finally {
if(randomAccessFile != null){
randomAccessFile.close();
randomAccessFile = null;
}
}
return 0;
}
当前程序已使用的句柄数量可进入文件夹 cd proc/进程ID/fd查看

image.png
当前文件句柄数量为
fd目录下文件总数量,图中有88个打开的文件句柄
java代码查询当前句柄数量
public static int getFdCount() {
File fdFile = new File("/proc/" + Process.myPid() + "/fd");
File[] files = fdFile.listFiles();
return null == files ? 0 : files.length;
}
在Android中能造成文件句柄泄漏主要有以下三类
1、Process
Process process = Runtime.getRuntime().exec("getprop ");
...
process.destroy();
Process使用完之后一定要调用 destroy()
2、各种Stream
InputStream
OutputStream
ByteArrayOutputStream
ByteArrayInputStream
DataOutputStream
DataInputStream
InputStreamReader
OutputStreamWriter
BufferedInputStream
BufferedOutputStream
FileInputStream
FileOutputStream
ZipOutputStream
ZipInputStream
FileReader
FileWriter
BufferedReader
BufferedWriter
RandomAccessFile
LineNumberReader
这些用完之后一定要记得close(),养成良好的编码习惯
3、Socket
很多时候句柄泄漏是socket不能正确的关闭导致的,所以在停止业务的时候,要保证socket都能正确的关闭
通过 slof -p 进程ID 可查看当前进程的句柄情况

image.png

image.png
大致可以定位句柄泄漏的类型