记录一次校招面试中暴露的不足 (细节拉满)

Posted by 好记性不如烂笔头 on 07-25,2020

概述

面试的岗位的 Java 后端开发。

面试题 1

面试官:

我看到你是计算机科班的,我们先来点基础的问题吧。一个函数 A ,调用一个函数 B ,内部的函数栈是怎么一个过程?入栈和出栈之类的?

说实话,这一手我确实没想到,这个基础问题就让我毫无防备,平时写了那么多代码,却没有研究过函数调用的底层原理,而这一个问题显然问底层的。唉,实在惭愧,然后面试完去网上找文章复习了一番。

当函数 A 被调用时,在内存中会创建一个函数 A 的栈帧,然后 A 中的变量依次入栈,随后是指令的入栈。

当遇到调用函数 B 这一个指令的时候,会先把该指令的后一条指令入栈,然后用一个栈底指针 (EBP) 指向这一条语句,表示这是函数 B 的栈底,用于函数返回时继续执行 A 中的指令。

然后创建函数 B 的栈帧,B 中的内容入栈,程序计数器跳到 B 的代码入口开始执行 B 中的指令。

当执行到 B 中的 return 语句时候,B 中的内容全部出栈,然后程序计数器跳到 EBP 的位置继续执行。

面试题 2

面试官:

你已经说到 Java 的垃圾回收是用可达性算法,那么哪些对象可以作为可达性算法的起点呢?(也就是 GC Root 对象)?

这一题纯属是我忘了,《深入理解 Java 虚拟机》这本书中已经讲得很清楚了,我很早之前看的,面试前复习疏漏了(想扇自己)。

可以当做 GC Root 的对象有:虚拟机栈中的方法内部引用类型所引用的对象;静态引用类型所引用的对象;被 synchronized 锁持有的对象......

这些对象可以作为可达性算法的起点,是因为在任意某个时刻,这些对象都不可能会被垃圾回收。

按照上述的三种对象分别解释:某个对象正在被某个方法的内部变量引用,自然不可能被垃圾回收;静态引用的对象本来就不会被垃圾回收;某个对象如果正在被某个持有锁的线程访问,这个对象也不可能被垃圾回收。

面试题 3

面试官:

系统调用是什么?什么时候会用到系统调用?系统调用的过程大致说一下?

嗯,这是我操作系统中的学习疏漏,我竟然不知道系统调用是啥...太菜了...面试完赶紧复习了。

线程有两种运行状态,一种是用户态,另一种是内核态。内核态的线程完全由操作系统进行控制,并且权限很高,可以直接读写内存或磁盘。

操作系统为了保护计算机资源不被随意破坏,所有想要更高操作权限的线程,都必须由用户态切换到内核态。而一次系统调用,就是指操作系统为内核态的线程提供的某种服务 (比如上面提到的读写内存或磁盘)。

需要系统调用的线程中,会有一条软中断指令。当执行到这条软中断指令时,调用 system_call 函数,并把需要的系统调用号放入寄存器 (不同的系统调用会使用不同的编号来区分)。

system_call 获取系统调用号,然后经过基址加变址运算,获得相关系统调用指令在内存中的位置,然后运行,最后把结果放入寄存器,供线程获取。

面试题 4

面试官:

怎么确定一个 TCP 连接是唯一的?一台机器的 TCP 连接数为什么会有限制?

第一个问题我知道,可是第二个问题我就不知道了,内心OS:SHIT。

用一个 4 元组来确定一个唯一的 TCP 连接:源 IP 地址,目的 IP 地址,源 port 号,目的 port 号。

对于单台服务器来说,由于只有 65535 个 port ,说明最多只能提供 65535 种不同的服务,但是建立的 TCP 连接个数大概在几万。而限制连接数的,主要是 socket 。

socket 是传输层套接字,每建立一个 TCP 连接,其上层就要建立一个 socket。而 socket 在 Linux 系统中是以文件描述符的形式存在。随着文件描述符变多,内存占用也会变多,所以操作系统会限制文件描述符的个数,从而也限制了 TCP 的连接的个数。