最近线上发生Java进程疯狂写磁盘的杯具,虽然没有造成大碍.由此可以想到如果在出现问题的时候能够快速定位到相应的线程,然后通过其它工具确定该线程堆栈信息,就可以很大程度上解决问题.

每个进程,在/proc目录下都对应一个子目录(以该进程id命名),关于该目录每个伪文件的内容,这里不一一细说。而进程所有的线程,都在task子目录下,目录结构是:/proc/[pid]/task/[tid]。其中/proc/[pid]/proc/[pid]/task/[tid]这两个目录下的文件名和格式基本上一致,主要是由于Linux不存在NT式的原生线程支持,线程也是以LWP(light weight processes)的方法运行。而这里只关心其中一个即io这个文件,该文件的内容实际上就是进程的实时io信息,例如:

根据 linux 内核文档(链接见末尾)说明,各个分量含义如下:
 
rchar :读计数器。所有传送给 read 系统调用的 count 的和值,显然,像输出到控制台 (printf) 这种操作,也会被计入该计数器。注意 read 并不一定每次都会读 count 指定的那么多数据。
read 系统调用原型: ssize_t read(int fd, void *buf, size_t count);
 
wchar :类似于 rchar ,只不过是写操作
syscr read 系统调用被调用的次数;
syscw write 系统调用被调用的次数;
read_bytes :实际发生块设备读的字节数;
write_bytes :实际发生块设备写的字节数;
对于我们而言,最后两个分量才是最有价值的,最能体现进程读写磁盘的情况。 
根据个人的研究,很多工具如 dstat 也是利用这个原理的。
 
一旦获取了线程 id ,就可以很方便的再使用 jstack 来分析该线程的调用堆栈,看看它究竟在干啥了。
 
最后,我也写了一个 python 脚本,可以输出某个进程前 10 个读写最大的线程 id

http://code.google.com/p/sdkfz000/source/browse/trunk/tio/tio.py