问题描述:
在开发imonitor工具时,遇到一个很严重的问题,在某些机型上运行实时监控时,会在打开监控后几秒钟就FC了,log显示异常为:
11-22 10:48:56.467 W/System.err( 557): java.io.IOException: Error running exec(). Command: [sh, -c, cat /sys/class/power_supply/battery/status] Working Directory: null Environment: null
11-22 10:48:56.467 D/iMonitor: CpuDataCollector( 557): getUserUsage(): 100* ((62622 - 62482)/(2378876 - 2375017))=3
11-22 10:48:56.468 W/System.err( 557): at java.lang.ProcessManager.exec(ProcessManager.java:211)
11-22 10:48:56.468 W/System.err( 557): at java.lang.Runtime.exec(Runtime.java:174)
11-22 10:48:56.468 W/System.err( 557): at java.lang.Runtime.exec(Runtime.java:129)
11-22 10:48:56.468 W/System.err( 557): at com.sprd.tool.d.a.a(Unknown Source)
11-22 10:48:56.468 W/System.err( 557): at com.sprd.tool.c.h.c(Unknown Source)
11-22 10:48:56.468 W/System.err( 557): at com.sprd.tool.c.b.run(Unknown Source)
11-22 10:48:56.468 W/System.err( 557): at java.util.Timer$TimerImpl.run(Timer.java:284)
11-22 10:48:56.468 W/System.err( 557): Caused by: java.io.IOException: Too many open files
11-22 10:48:56.469 W/System.err( 557): at java.lang.ProcessManager.exec(Native Method)
11-22 10:48:56.469 W/System.err( 557): at java.lang.ProcessManager.exec(ProcessManager.java:209)
11-22 10:48:56.469 W/System.err( 557): ... 6 more
问题分析:
由于在打开监控时,会每秒大量cat读取手机中的系统参数文件,导致too many open files异常。通过 cat /proc/sys/fs/file-max可以查看系统允许打开的最大句柄数,但终归是有个极限的,随着时间推移,打开的文件数一定会达到上限而发生异常,最正确的解决方案是每读一次文件就关一个文件。
解决方案:
try {
proc = runtime.exec(args);
InputStream inputstream = proc.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(
inputstream);
bufferedreader = new BufferedReader(inputstreamreader);
// read the ls output
String line = "";
sb = new StringBuilder(line);
while ((line = bufferedreader.readLine()) != null) {
...
}
if (proc.waitFor() != 0) {
Log.d(TAG, "exit value = " + proc.exitValue());
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (bufferedreader != null) {
try {
bufferedreader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
对于new BufferReader(new InputStreamReader(new InputStream(...)));
这种多层次的流调用,只需对最外层执行close(),外层的会依次关闭里层的。