0%

面试可以问的问题

一、性格

  1. 介绍一下自己
  2. 被刷了怎么办
  3. 以后的打算

二、技术

  1. 如何学习一门新的语言
    • 记笔记
    • 做实践
  2. 做过什么项目,担任什么工作,怎么做
    • 对于项目的架构的了解
    • 是不是水
  3. 遇到技术问题怎么办

1. linux

1.1. IO

  1. Linux 的 system I/O 和 std I/O 有什么区别?各自的效率怎样?
    • system io,read/write
    • std io,fread/fwrite
  2. linux下的io多路复用有几种方式? 各自有什么优缺点?(提问:水平触发和电平触发的区别)
    • select/epoll

1.2. 命令执行

Shell命令执行结果通常包含哪些,(返回值0或非0,标准输出和标准出错的信息),在其它语言(例如C)中如何才能正确获取所有的命令执行结果,提高程序的用可用性和可查错性(c可自行封装函数捕捉标准输出和标准出错,其它语言可以用类似功能的api,反正system函数不是个好选择)

1.3. 命令

  1. 尽量多的说出linux常用命令
  2. 怎么查看端口占用情况
    2.netstat -anp | grep [port] 或者用lsof -i:[port]
  3. 统计出一个目录下,包含某个字符串的文本文件
    3.grep -rnw “[str]” [dir]
  4. 使用top命令后,一般关注那些参数
    4.譬如 wa id si ,让其介绍参数所代表的意义
    6.7% us — 用户空间占用CPU的百分比。

0.4% sy — 内核空间占用CPU的百分比。

0.0% ni — 改变过优先级的进程占用CPU的百分比

92.9% id — 空闲CPU百分比

0.0% wa — IO等待占用CPU的百分比

0.0% hi — 硬中断(Hardware IRQ)占用CPU的百分比

0.0% si — 软中断(Software Interrupts)占用CPU的百分比

1.4. linux启动

加载BIOS
读取MBR(硬盘上第0磁道第一个扇区被称为MBR)
Boot Loader(Boot Loader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核做好一切准备。其中Grub、Lilo和spfdisk是常见的Loader)
加载内核(根据grub设定的内核映像所在路径,系统读取内存映像,并进行解压缩操作。)
用户层init依据inittab文件来设定运行等级
init进程执行rc.sysinit(Linux系统执行的第一个用户层文件就是/etc/rc.d/rc.sysinit脚本程序,它做的工作非常多,包括设定PATH、设定网络配置(/etc/sysconfig/network)、启动swap分区、设定/proc等等)
启动内核模块(具体是依据/etc/modules.conf文件或/etc/modules.d目录下的文件来装载内核模块)
执行不同运行级别的脚本程序(根据运行级别的不同,系统会运行rc0.d到rc6.d中的相应的脚本程序,来完成相应的初始化工作和启动相应的服务)
执行/etc/rc.d/rc.local(rc.local就是在一切初始化工作后,Linux留给用户进行个性化的地方。)
执行/bin/login程序,进入登录状态

1.5. 文件系统

硬连接:指通过索引节点来进行连接。在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(Inode Index)。
在Linux中,多个文件名指向同一索引节点是存在的。一般这种连接就是硬连接。硬连接的作用是允许一个文件拥有多个有效路径名,
这样用户就可以建立硬连接到重要文件,以防止“误删”的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的连接。
只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。
也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除。

软连接:另外一种连接称之为符号连接(Symbolic Link),也叫软连接。软链接文件有类似于Windows的快捷方式。
它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。

1.6. 进程线程

1) 多线程同步的几种方式?

互斥锁、条件变量、读写锁、信号量

2) 什么是孤儿进程? 什么是僵尸进程?如何判断一个进程是否为孤儿进程/僵尸进程? 如何产生, 有什么危害?

  • 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
  • 僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

3) 进程间通信方式:

  • 管道:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
  • 信号量: 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
  • 消息队列: 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
  • 共享内存:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
  • 套接字: 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

4) fork、vfork和clone的区别

  • fork和vfork都是调用clone,但是传的标志位不同
  • vfork执行后,除非调用execvfork_done,否则不会让父进程继续运行,主要是因为当时没有写时拷贝的机制而建立的
  • fork执行后,父子进程都会返回继续执行,一般先让子进程运行,因为可能调用了exec就不依赖共享的内存页。如果父进程先运行,写了共享的内存页会拷贝一份造成多余的拷贝操作

1.7. 内存管理

  1. malloc最多申请多大内存
  2. Linux 内存分区是怎样的,总共分为几个区?
  3. ps命令中,VSZ和RSS分别代表什么?两者有什么联系和区别?

1.考虑 32 位系统 4G 内存:3G 给用户,1G 给内核。用户区:栈区、堆区、全局区(静态区)、常量区、程序代码区(最好能画出来)。
2.虚拟内存占用空间和实际物理内存占用空间。VSZ包括进程可访问的所有内存,如包括swap、动态链接库、堆栈中的内存;RSS包括动态链接库,堆栈内存,但不包括swap中的内存。

2. C/C++

2.1. 内存管理

在C++中内存分成5个区,分别是堆、栈、全局/静态存储区、常量存储区和代码区;
a、栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区,里面的变量通常是局部变量、函数参数等。
b、堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如
果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
c、全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在
C++里面没有这个区分了,他们共同占用同一块内存区。
d、常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改)。
e、代码区 (.text段),存放代码(如函数),不允许修改(类似常量存储区),但可以执行(不同于常量存储区)。

2.2. 编译原理

  1. 符号表
  2. 符号隐藏
  3. 动态库符号引入

1) 下面语句是否有错,解释一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const int a;
// 有错,没有对常量进行初始化

static int b;
// 没问题,虽然尽量要求初始化

char &c;
// 有错,没有对左值定义进行初始化

int *d; d = new int[10]; delete d;
// 有错,需要delete[] d;,但是现在编译器可能帮你优化了,不造成内存泄漏,还是不建议这样写

(a+b)++
// 有错,自增操作符需要是左值,给的是右值

2) 链接过程的重定位

c语言-链接过程的重定位

2.3. 调试

  1. 跟踪程序系统调用
  2. 堆栈信息打印
  3. gdb,打印堆栈命令
    • bt

2.4. 指针

1) 说明下面语句的区别

1
2
3
4
5
6
7
8
9
10
11
char *p = "hello";
// 使用char *指向常量空间,编译会报warning。*p和p[n]修改值可以编译通过,但是实际不可修改,修改会崩溃。p本身的指向可以修改为其他内存

const char *p = "hello";
// 使用const char *指向常量空间,编译没问题。*p和p[n]不允许修改,编译会报错。p本身可以修改为指向其他内存

char * const p = "hello";
// 使用char *指向常量空间,编译会报warning。*p和p[n]修改值可以编译通过,但是实际不可修改,修改会崩溃。p本身也不能指向其他位置

const char * const p = "hello";
// 使用const char *指向常量空间,编译没问题。*p和p[n]不允许修改,编译会报错。p本身也不能指向其他位置

2) 给出下面的结果并说明原因

(1)
1
2
int arr[5] = {1, 2, 3, 4, 5};
printf("%d", *(*(&arr+1)-1));
  • 结果是5
1
2
3
4
5
&arr;           // int (*)[5]
&arr+1; // 地址偏移5个int
*(&arr+1); // 指向arr后5个int的地方
*(&arr+1)-1; // 指向arr最后一个元素的地址
*(*(&arr+1)-1); // 5

2.5. 设计思想

1) RAII机制

  • resource acquisition is initialization 资源获取即初始化
  • 核心是将资源和对象生命周期绑定,对象创建就获取资源,对象销毁就释放资源
  • RAII机制是指利用对象的销毁机制来实现内存资源的生命周期管理
  • 比如智能指针,利用智能指针的析构的时候,调用delete将指向的内存释放,编程者不用关心释放时机
  • lock_guard,利用栈变量在作用域离开后自动销毁的机制实现自动解锁

3. 网络

2.1. TCP/IP

1) udp可以调用connect嘛?和tcp调用connect有什么不同?

可以, 没有实际的握手,只是指定了目的ip和端口,可以使用send recv收发包

2) udp可用调用bind嘛?

可以,绑定源ip和源端口

3) listen第二个参数的作用(全连接队列、半连接队列),半连接队满会有什么影响?全连接队列满会有什么影响?

设置全连接队列长度,但是内核参数somaxconn必须也要放开才可以

对于SYN半连接队列的大小是由(/proc/sys/net/ipv4/tcp_max_syn_backlog)这个内核参数控制的,有些内核似乎也受listen的backlog参数影响,取得是两个值的最小值。
当这个队列满了,不开启syncookies的时候,Server会丢弃新来的SYN包,而Client端在多次重发SYN包得不到响应而返回(connection time out)错误。
但是,当Server端开启了syncookies=1,那么SYN半连接队列就没有逻辑上的最大值了,并且/proc/sys/net/ipv4/tcp_max_syn_backlog设置的值也会被忽略

当accept队列满了之后,即使client继续向server发送ACK的包,也会不被响应,此时ListenOverflows+1,同时server通过/proc/sys/net/ipv4/tcp_abort_on_overflow来决定如何返回,0表示直接丢弃该ACK,1表示发送RST通知client;
相应的,client则会分别返回read timeout 或者 connection reset by peer。

4) TIME_WAIT状态是主动关闭的一方进入还是被动关闭的一方进入?为什么有这个状态,要解决什么问题?如何减少服务端的TIME_WAIT?

  • 主动关闭方会发送fin收到ack后,等对端发送的fin回复ack后进入TIME_WAIT状态。
  • 为了防止自己回复的ack对方没有收到,如果对方没有收到会重发fin,这时等待的socket可以处理此fin重传ack而让对方可靠关闭。2msl就是对方重传fin包的时间,对方发送的fin包到自己经过1个msl,发送ack如果对方没有收到会等2个msl(Maximum Segment Lifetime)再发送,自己收到第二个fin包和第一个fin包之间间隔2个msl,所以要等待这么久。
  • 调整内核参数
    • net.ipv4.tcp_tw_reuse: time_wait状态的端口是否可重用
    • net.ipv4.tcp_timestamp: 和上面配置一起,当配置了上面的配置,在新建立连接时如果time_wait间隔超过此时间(单位s)就可以复用
    • net.ipv4.tcp_max_tw_buckets: 当time_wait超过此值,会重置前面的连接

5) 描述一下浏览器访问一个URL的全过程。

从ARP查找,DNS查找,三次握手,请求,回复等。

6) 谈下网络拥塞和TCP的拥塞控制机制(什么是:慢启动、拥塞避免、快速重传 、快速恢复)

网络拥塞现象是指到达通信子网中某一部分的分组数量过多,使得该部分网络来不及处理,以致引起这部分乃至整个网络性能下降的现象,
严重时导致网络通信业务陷入停顿出现死锁现象。拥塞控制是通过拥塞窗口处理网络拥塞现象的一种机制。
TCP的拥塞控制由4个核心算法组成:慢启动、拥塞避免、快速重传 、快速恢复。

慢启动+拥塞避免:

发送方会维护一个拥塞窗口cwind的变量并且设置一个初始的ssthresh(慢启动阀值),这个变量会随着网络的拥塞状况发生改变。
刚开始发送数据的时候,发送方会将cwind的值置为1(一般为一个MSS)。后面每次收到ack包后就将cwind的值翻倍直到ssthresh。
到达ssthresh后,进入拥塞控制阶段,这个时候,cwind不再指数级增长,而是每次收到一个ack包,cwind增加1(加法增大)。
直到发生超时的时候,将ssthresh的值置为当前cwind值的一半,然后将cwind值回退为1,重新开始慢启动。如此反复。
慢启动依赖“超时”来调整ssthresh的值,而在等待超时的时间中,tcp连接会一直处于空闲阶段。
而一旦超时,cwind将从1开始增加,这样无疑会影响tcp的传输效率,所以,快速重传和快速回复为了弥补这个缺点而产生。

快速重传:

接受方在接收到失序报文的时候,应该立即发出重复确认,当发送方接受到三个重复确认的时候就会知道丢包了,而不是等到超时。
eg:recv方接受到M1, M2, M4, M5, M6的时候,因为M3丢失,接受方在接收到4-6的时候会对连发三个对M2的重复确认,
这样,发送方就知道丢包了,然后调整ssthresh的值为当前cwnd值的一半。与之前不同的是,快速重传会结合快速恢复。
发生超时后,不再将cwnd的值重新置为1,而是从赋值为新的ssthresh的值,然后加法增

三、利益相关

  1. 时间冲突怎么做