java程序运行时发生的系统调用

875 阅读3分钟

程序无法直接访问数据(硬件:磁盘、网卡),程序需要通过内核访问,内核提供syscall,syscall的方法不能直接调用(保护模式),所以就有了软中断,中断作用在cpu中,cpu收到中断后,cpu会根据中断号去内核中找对应的callback...

程序测试

下面通过一个简单的例子进行说明,下面这段代码是测试socket简单的一个方法,应该比较好理解(其实就是通过多线程解决多连接的问题),将下面这个java文件放在linux执行看下

public class TestSocket {
    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(8090);
        System.out.println("step1:new ServerSocket(80)");
        while (true){
            Socket client = server.accept();
            System.out.println("step2:client\t"+client.getPort());
            new Thread(() ->{
                try {
                    InputStream in = client.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                    while (true){
                        System.out.println(reader.readLine());
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }).start();
        }
    }
}

程序抓取

通过下面这个命令抓取上面程序执行时对于内核有没有发生系统调用

strace -ff -o ./ooxx java TestSocket

执行后可以看到打印了第一句话,说明程序已经执行,发生了阻塞

通过其他窗口进入这个文件夹发现产生了一堆文件

其实这些文件都是线程,那么哪个文件是主线程呢?可以通过代码中的关键字查找下

-- 查找包含step1 的文件
grep 'step1' ./*

果然其中最大的这个163文件有个"write(1, "step1:new ServerSocket(80)", 26) = 26"

可以打开这个文件看下,可以找到这个操作在文件中的位置(具体的含义我们后面再分析)

进程线程分析

另外可以通过jps查看线程

在linux中一切皆文件,可以看看162这个进程中有哪些东西,可以进入linux根目录下的/proc/进程id 目录中查看,有看到一堆东西

先看下task文件,打开这个会发现这些数字是不是和上面ooxx.*是一样的呢,没错其实这个jdk进程中的线程,知道这个之后你就可以查看自己应用下的线程数量

还有一个目录fd,可以看到一些数据这里面的东西叫文件描述符,任何一个程序都有io,0、1、2是三个基本的io

  • 0 标准输入
  • 1 标准输出
  • 2 错误输出

这些流在java中是对象,在操作系统中都是文件,通过数字的方式代表,类似于java中的变量

  • 3、4 是java程序特有的库
  • 5、6 其实是我们的程序启动后的server会监听8090,两个分部是ipv4、ipv6

通过网络状态这个命令 netstat -natp;可以看到state是LISTEN状态,只有服务端有监听状态,客户端可以通过这个端口号连接

系统调用分析

那么我们用nc命令连接看看,可以看到一个连接进来java程序中多一个记录,并且文件描述符相比之前也多了一个socket

nc localhost 8090

网络连接

文件描述符

然后一开始程序所在的文件夹,找到主线程,打开后查找先连接的端口号49482;可以看到

accept(6, {sa_family=AF_INET, sin_port=htons(49482), sin_addr=inet_addr("127.0.0.1")}, [16]) = 7

回顾下之前的方法有个server.accept(),内核中也有accept,可以理解java中的一些方法是对内核的包装;在主线程的文件中可以看到生成的文件描述符以及程序执行发生具体的系统调用

你也可以使用man命令查看各种指令的作用; 先介绍到这里吧,后面会继续介绍下nio的一些内容