典型面试题
Linux 系统开发常见面试题 Linux 网络开发常见面试题 常见算法笔试题
腾讯C++面试
- 大端与小端的概念?各自的优势是什么?
- TIME_WAIT状态的产生、危害、如何避免?
- select/poll/epoll的区别
- 系统调用与库函数的区别
- 守护进程、僵尸进程、孤儿进程的概念
- TCP和UDP的区别
- 请画出TCP的头部
- new和malloc的区别
- 指针和引用的区别
- 为什么TCP叫数据流模式,UDP叫数据报模式?
- 简述一下TCP的滑动窗口机制
- TCP的拥塞控制机制是什么?请简单说说。
- 为什么析构函数要设为虚函数?
- linux下你常用的命令有哪些?
- static关键字的作用?
- C++的内存分区
- C++对象的内存布局
- vector、map/multimap、unordered_map/unordered_multimap的底层数据结构,以及几种map容器如何选择?
- 栈溢出的原因及解决办法
- 内存泄漏怎么产生的?如何避免?
- TCP建立连接为什么需要三次?断开连接又为什么需要四次?
- core产生的原因,如何调试定位问题?
- 死锁产生的四个条件,死锁发生后怎么检测和恢复?
- 堆和栈的区别
- 简单描述一下TCP三次握手和四次挥手的过程
- 数据库索引的优缺点
- 数据库的三范式
- 如何在一个不安全的环境中实现安全的数据通信
- 说几个C++ 11的新特性
- C++ STL中vector内存用尽后,为啥每次是两倍增长,而不是3倍或其他倍数?
- 阻塞IO、非阻塞IO、同步IO、异步IO的区别?
- 分时系统与实时系统的区别?
- 除了sleep之外,usleep也是linux系统调用,它号称自己是微秒级的,你相信它真的有这么快吗?为什么?
- 简述一下ping的原理
- 进程调度算法有哪些?Linux使用的什么进程调度方法?
- static_cast和dynamic_cast的区别
- DNS使用什么协议
- traceroute命令有什么作用?原理是什么?
- 什么是事务?事务有哪些特性?
- MySQL的引擎InnoDB和MyISAM的区别。
来源及参考答案见: lisong694767315的CSDN博客
腾讯python电话面试
电话面试的问题大致分为项目经历、计算机基础和python基础三个部分。
计算机基础方面问了线程和进程的区别,http三次握手的过程,TCP/IP协议栈等,进程间通信时共享内存、管道的实现方式等,不算太难。
而Python语言方面问得更深一些,除了数据类型、用法之外,还问到了这几个问题:
(1)元组和列表的区别?为什么python要设计一个元组类型?它有什么用途是列表不能替代的?
元组和列表相比有一个很重要的区别,元组是一种不可变类型。正因为这个原因,元组能做一些列表不能做的事情,例如,用做一个字典的 key(必须是可哈希的对象)。另外当处理一组对象时,这个组默认是元组类型。
最好使用不可变类型变量的一个情况是,如果你在维护一些敏感的数据,并且需要把这些数据传递给一个并不了解的函数(或许是一个根本不是你写的 API),作为一个只负责一个软件某一部分的工程师,如果你确信你的数据不会被调用的函数篡改,你会觉得安全了许多。
(2)python解释器是怎么运行的?或者说,当你在命令行输入python hello.py之后,内部的运行过程是怎样的?参考文章
(3)知道python的duck类型吗?参考文章
(4)解释一下python的装饰器,以及使用装饰器有什么优点?参考文章
(5)知道GIL吗?参考文章
还有一些python的面试题:
其他问题
-
逻辑地址、线性地址、物理地址之间的关系
软件一旦从硬盘加载到内存中,就拥有了最大的内存空间(如果是32位机,那么这个空间就是
2^32=4G
),这些空间在进程中是分段管理的(代码段、数据段、堆、栈等)。寻址方式是段地址+偏移量,即逻辑地址。逻辑地址需要转换为线性地址,线性地址经过计算得到页地址,最后得到物理地址。例:当采用4KB分页大小时,线性地址的高10位为页目录项在页目录表中的编号,中间10位为页表中的页号,其余12位为偏移地址;当采用4MB分页机制时,则高10位是页号,低22位为偏移地址。
早先的线性地址就是物理地址,但是采用分页机制后,线性地址就不再是物理地址了。通过分页可以提高内存的使用率。
无论你申请1个字节的内存,还是1kB的内存,都会占用一个页的内存。所以为了提高内存的使用率,最好是以4K的整数倍来申请内存空间。
-
虚拟内存(《操作系统概念》第九章)
原理:内存空间不够的时候可以将程序不需要用到的数据交换到磁盘空间上去,以达到扩展内存空间的目的。
-
全局变量能否定义在可被多个
.c
文件包含的头文件中?为什么?不可以。一般来说编译会报错,因为会造成重复定义。可以在一个
.c
文件中定义,然后在一个头文件中用extern
进行声明,对于要用到这个全局变量的代码文件,只要包含此头文件即可。 -
什么是内存泄漏?怎样定位?如何避免?
内存泄漏是指由于疏忽或错误造成程序未能释放已经不再使用的内存的情形。为避免内存泄漏,要保证malloc/free、new/delete成对使用。一些检测工具也是利用这个原理。我们可以通过查看每个进程内存使用的情况来定位,如果进程使用的内存在逐步增加,超出了程序正常运行所需,那么就发生了内存泄漏。
-
什么是线程安全?
所谓线程安全,是指在多线程程序中,不同线程在访问同一个资源,能成功进行访问,不会产生错误。如果产生错误,那么就是线程不安全的。通常为了线程安全性,采用互斥锁,或者P、V操作进行。
-
什么是函数可重入?
可重入函数主要用于多任务环境中。一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度去执行下一段代码,而返回控制时不会出现什么错误。不可重入的函数由于使用了一些系统资源,比如全局变量区、中断向量表等,如果被中断的话可能出现问题,这类函数是不能运行在多任务环境下的。编写可重入函数时,若使用全局变量,则应通过关中断、信号量(P、V操作)等手段对其加以保护。
-
Linux是怎样管理内存的?
在linux系统中,采用逻辑地址、线性地址、物理地址来管理内存。程序运行是在逻辑地址之上。为解决内存使用率(内存碎片)的问题,采用分页的方法,即把物理内存空间分页来进行管理,每个内存页占用4kB的空间。Linux系统采用伙伴算法来管理内存空间。
-
进程和线程的差别?
(1)线程是指进程内的一个执行单元,也是进程内可调度的实体。
(2)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。
(3)并发性:不仅进程之间可以并发执行,同一进程的多个线程之间也可并发执行。
(4)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源。
(5)系统开销:在创建或撤销进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤销线程的开销。
-
如何从1亿个数字中取出最大的100个?
采用电话号码分析树的设计原理,假设每个整数有32位,建立一棵二叉树,左节点都为0,右节点都为1,这个整数的32位的每一位都是一个节点,高位放在上层。此节点的结构包括如下两个元素:是否是数据、相同的数据当前有多少个。
考虑到内存不够,不可能把这1亿个数据都建立在这棵树上,当此二叉树有了100个数字后(包括相同的数字),每插入一个数字时,就把最小的(靠最左边的)数字删除掉。
-
经验表明 80%-90% 的性能调优是在应用级做的,而不是在数据库级。
-
两个整数集合A和B,求其交集?
(1)读取集合A中的整数,将读到的整数插入到map中,并把相应的值设为1;
(2)读取集合B中的整数,如果该整数在map中存在且值为1,则将此数加入到交集中,并将map中的对应值改为2.
-
给定40亿个不重复的unsigned int型整数,未排序,然后再给几个数,如何快速判断这几个数是否在那40亿个数当中?
unsigned int
的取值范围是0到2^32-1
。我们可以申请连续的2^32/8=512MB
的内存,用一个bit对应一个unsigned int数字是否出现过。遍历这40亿个数,并做相应标记。 -
进程一定会遇到的两个信号是什么?
一个是引起进程终止执行的SIGSTOP信号,另一个是引起进程退出的SIGKILL信号。这两个信号如果不处理,进程申请的资源就无法回收。
-
i++
是否是原子操作?如果是32位系统,且i没有跨页,那么是原子操作;如果是64位系统,则一定不是原子操作。
i++
被编译成多条指令,由于中途没有写回内存的操作,系统应该不会中断这个操作,因为一旦中断,寄存器的值就会被冲掉而导致错误,所以可认为是原子操作,即在单线程下是安全的。但是在多线程的情况下,考虑到编译优化和寄存器的作用,并不能保证多个线程同时操作i能同步。所有系统调用都是以原子操作方式执行的。write系统调用在buf大小不超过内核缓存的时候是原子操作。
-
说说linux的各类同步机制。
信号量(信号灯):pv操作;
互斥锁:计数器;
读写锁:
条件变量:条件变量为我们提供了另一种线程间同步的方法,然而,互斥量是通过控制线程访问数据来实现同步,条件变量允许线程同步是基于实际数据的值。如果没有条件变量,程序员需要让线程不断地轮询,以检查是否满足条件。由于线程处在一个不间断的忙碌状态,所以这是相当耗资源的。条件变量就是这么一个不需要轮询就可以解决这个问题的方法。条件变量总是跟互斥锁(mutex lock)一起使用。参考文章
-
列举说明linux系统的各类异步机制。
比如TCP的send函数,它只是把数据写到缓存,并没有到达对端。
-
在C中主流编译器对sizeof(空结构体)编译后执行的结果是0,而在C++中主流编译器对sizeof(空结构体)或对sizeof(空类)编译后执行的结果均为1. 关于sizeof
-
设计一个洗牌算法,并说明其复杂度。
for(0<i<55)
随机产生一个数k(0<k<5)
,与第i张互换。时间复杂度O(n)。 -
注意C++中,如果自己定义了一个构造函数,那么系统就不会自动添加默认构造函数了,如果要用的话必须显式写出来。
-
什么时候可以为类定义一个静态成员变量?
当希望类的所有对象共享一个相同的属性值时,就可以定义一个静态成员变量。或者希望不同对象间能相互通讯,也可通过静态成员变量。
-
为什么要把析构函数声明为虚析构函数? (实现多态的需要)这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。
当然,并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。
-
关键字
volatile
有什么含义?volatile
关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其他线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址对稳定访问。声明时的语法是int volatile iValue;
。当要求使用volatile
声明的变量时,系统总是从它所在的内存中读取数据并且立即保存,即使它前面的指令刚刚读取过该数据。 -
总结
const
的作用。(1)阻止一个变量被改变。
(2)对指针来说,可以指定指针本身是const,也可以指定其指向的数据为const,也可以二者都是const。
(3)在函数声明中,const修饰形参,表示在函数内部不得改变其值。
(4)const修饰成员函数(const放在声明语句的分号之前),表示其不得修改成员变量的值。
(5)const修饰成员函数的返回值类型,表示其返回值不得为左值。
-
C++的空类中,默认产生哪些类成员函数?
(1)默认构造函数;
(2)默认拷贝构造函数;
(3)默认赋值操作符(operator=);
(4)默认取址操作符(operator&);
(5)默认析构函数。