腾讯后台开发面试题及答案

这篇博客详细总结了腾讯后台开发的面试知识点,涵盖了网络状态、内存管理、进程间通信、信号处理、编译链接、数据结构、算法、操作系统、网络编程等多个方面。重点讨论了netstat命令的输出、tcpdump的用途、ipcs和ipcrm命令的使用、进程间通信机制如共享内存、管道、信号量等,并强调了多线程和多进程的区别。此外,还提到了TCP与UDP的区别、内存泄漏检测、进程调度、系统调用与库函数的区别、Linux的内存管理机制以及任务调度机制。面试中常见的问题如TCP的TIME_WAIT状态、信号处理、内存泄漏检测、守护进程的实现、Linux系统的各类异步机制、exit()与_exit()的区别等都有涉及。
摘要由CSDN通过智能技术生成

转自:http://blog.csdn.net/ibmfahsion/article/details/11992403?utm_source=tuicool&utm_medium=referral


简单归纳:fd只是一个整数,在open时产生。起到一个索引的作用,进程通过PCB中的文件描述符表找到该fd所指向的文件指针filp。

文件描述符的操作(如: open)返回的是一个文件描述符,内核会在每个进程空间中维护一个文件描述符表, 所有打开的文件都将通过此表中的文件描述符来引用; 
而流(如: fopen)返回的是一个FILE结构指针, FILE结构是包含有文件描述符的,FILE结构函数可以看作是对fd直接操作的系统调用的封装, 它的优点是带有I/O缓存

每个进程在PCB(Process Control Block)即进程控制块中都保存着一份文件描述符表,文件描述符就是这个表的索引,文件描述表中每个表项都有一个指向已打开文件的指针,现在我们明确一下:已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体。

linuxos:

netstat 显示网络状态

Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics),masquerade 连接,多播成员 (Multicast Memberships) 等等。

从整体上看,netstat的输出结果可以分为两个部分:

一个是Active Internet connections,称为有源TCP连接,其中"Recv-Q"和"Send-Q"指%0A的是接收队列和发送队列。这些数字一般都应该是0。如果不是则表示软件包正在队列中堆积。这种情况只能在非常少的情况见到。

另一个是Active UNIX domain sockets,称为有源Unix域套接口(和网络套接字一样,但是只能用于本机通信,性能可以提高一倍)。
Proto显示连接使用的协议,RefCnt表示连接到本套接口上的进程号,Types显示套接口的类型,State显示套接口当前的状态,Path表示连接到套接口的其它进程使用的路径名。

 

tcpdump主要是截获通过本机网络接口的数据,用以分析。能够截获当前所有通过本机网卡的数据包。它拥有灵活的过滤机制,可以确保得到想要的数据。

用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者的定义对网络上的数据包进行截获的包分析工具。 tcpdump可以将网络中传送的数据包的“头”完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助你去掉无用的信息。

 

ipcs:检查系统上共享内存的分配

用途

报告进程间通信设施状态。

ipcs 命令往标准输出写入一些关于活动进程间通信设施的信息。如果没有指定任何标志,ipcs 命令用简短格式写入一些关于当前活动消息队列共享内存段、信号量、远程队列和本地队列标题。

 

 

 

Linuxipcs指令的用法详解。ipcsLinux下显示进程间通信设施状态的工具。可以显示消息队列、共享内存和信号量的信息。对于程序员可能更有用些,普通的系统管理员一般用不到此指令。

ipcrm:手动解除系统上共享内存的分配

用途
  删除消息队列、信号集、或者共享内存标识。

 

 

 

(如果这四个命令没听说过或者不能熟练使用,基本上可以回家,通过的概率较小 ^_^ ,这四个命令的熟练掌握程度基本上能体现面试者实际开发和调试程序的经验)

 

查看cpu信息

        #cat /proc/cpuinfo

   # cat /proc/meminfo

查看硬盘信息

        # df -lh

更详细的信息

       # cat /proc/scsi/scsi

查看网卡信息

        # dmesg | grep eth

更常用的命令(显示系统核心版本号、名称、机器类型等)

       # uname -a

 

cpu 内存硬盘等等与系统性能调试相关的命令必须熟练掌握,设置修改权限 tcp网络状态查看各进程状态抓包相关等相关命令必须熟练掌握

awk sed需掌握

共享内存的使用实现原理(必考必问,然后共享内存段被映射进进程空间之后,存在于进程空间的什么位置?共享内存段最大限制是多少?)

$sysctl kern.ipc.shmmax
kern.ipc.shmmax: 33554432

Linux的2.2.x以后的内核版本支持多种共享内存方式,比如:内存映射mmap、POSIX共享内存、System V共享内存;

 

共享内存定义:共享内存是最快的可用IPC(进程间通信)形式。它允许多个不相关的进程去访问同一部分逻辑内存。共享内存是由IPC为一个进程创建的一个特殊的地址范围,它将出现在进程的地址空间中。其他进程可以把同一段共享内存段“连接到”它们自己的地址空间里去。所有进程都可以访问共享内存中的地址。如果一个进程向这段共享内存写了数据,所做的改动会立刻被有访问同一段共享内存的其他进程看到。因此共享内存对于数据的传输是非常高效的。

共享内存的原理:共享内存是最有用的进程间通信方式之一,也是最快的IPC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。

c++进程内存空间分布(注意各部分的内存地址谁高谁低,注意栈从高到低分配,堆从低到高分配)

ELF是什么?其大小与程序中全局变量的是否初始化有什么关系(注意未初始化的数据放在bss段)

Linux ELF  ELF = Executable and Linkable Format,可执行连接格式,是UNIX系统实验室(USL)作为应用程序二进制接口(Application Binary Interface,ABI)而开发和发布的。扩展名为elf。工具接口标准委员会(TIS)选择了正在发展中的ELF标准作为工作在32位INTEL体系上不同操作系统之间可移植的二进制文件格式。假定开发者定义了一个二进制接口集合,ELF标准用它来支持流线型的软件发展。应该减少不同执行接口的数量。因此可以减少重新编程重新编译的代码。

 

BSS段

可执行程序包括BSS段、数据段代码段(也称文本段)。

BSS(Block Started by Symbol)通常是指用来存放程序中未初始化的全局变量静态变量的一块内存区域。特点是:可读写的,在程序执行之前BSS段会自动清0。所以,未初始的全局变量在程序执行之前已经成0了。

注意和数据段的区别,BSS存放的是未初始化的全局变量静态变量,数据段存放的是初始化后的全局变量和静态变量。

UNIX下可使用size命令查看可执行文件的段大小信息。如size a.out。

 

可执行文件:包含了代码和数据。具有可执行的程序。

可重定位文件:包含了代码和数据(这些数据是和其他重定位文件和共享的 
object
文件一起连接时使用的)

共享object文件(又可叫做共享库):包含了代码和数据(这些数据是在连接
时候被连接器ld和运行时动态连接器使用的)。

使创建共享库容易,使动态装载和共享库的结合更加容易。在ELF下,在C++ 
中,全局的构造函数和析构函数在共享库和静态库中用同样方法处理。

使用过哪些进程间通讯机制,并详细说明(重点)

makefile编写,虽然比较基础,但是会被问到

mkdir mf

cd mf

vim makefile

hello.o:hello.c hello.h

       gcc –c hello.o -Lm

make

./hello

gdb调试相关的经验,会被问到

GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是在 UNIX平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。

一般来说,GDB主要帮助你完成下面四个方面的功能:

1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。

2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式

3、当程序被停住时,可以检查此时你的程序中所发生的事。

4、动态的改变你程序的执行环境。

《GDB使用手册》

gcc -g -o hello hello.c 。

GDB常用命令简介
  GDB的命令很多,本文不会全部介绍,仅会介绍一些最常用的。在介绍之前,先介绍GDB中的一个非常有用的功能:补齐功能。它就如同Linux下SHELL中的命令补齐一样。当你输入一个命令的前几个字符,然后输入TAB键,如果没有其它命令的前几个字符与此相同,SHELL将补齐此命令。如果有其它命令的前几个字符与此相同,你会听到一声警告声,再输入TAB键,SHELL将所有前几个字符与此相同的命令全部列出。而GDB中的补齐功能不仅能补齐GDB命令,而且能补齐参数。
  本文将先介绍常用的命令,然后结合一个具体的例子来演示如何实际使用这些命令。下面的所有命令除了第一条启动GDB命令是在SHELL下输入的,其余都是GDB内的命令。大部分GDB内的命令都可以仅输入前几个字符,只要不与其它指令冲突。如quit可以简写为q,因为以q打头的命令只有quit。List可以简写为l,等等
3.1 启动GDB
  你可以输入GDB来启动GDB程序。GDB程序有许多参数,在此没有必要详细介绍,但一个最为常用的还是要介绍的:如果你已经编译好一个程序,我们假设文件名为hello,你想用GDB调试它,可以输入gdb hello来启动GDB并载入你的程序。如果你仅仅启动了GDB,你必须在启动后,在GDB中再载入你的程序。
3.2 载入程序 === file
  在GDB内,载入程序很简单,使用file命令。如file hello。当然,程序的路径名要正确。
  退出GDB === quit
  在GDB的命令方式下,输入quit,你就可以退出GDB。你也可以输入'C-d'来退出GDB。
3.3 运行程序 === run
  当你在GDB中已将要调试的程序载入后,你可以用run命令来执行。如果你的程序需要参数,你可以在run指令后接着输入参数,就象你在SHELL下执行一个需要参数的命令一样。
3.4 查看程序信息 === info
  info指令用来查看程序的信息,当你用help info查看帮助的话,info指令的参数足足占了两个屏幕,它的参数非常多,但大部分不常用。我用info指令最多的是用它来查看断点信息。
3.4.1 查看断点信息
info br
br是断点break的缩写,记得GDB的补齐功能吧。用这条指令,你可以得到你所设置的所有断点的详细信息。包括断点号,类型,状态,内存地址,断点在源程序中的位置等。
3.4.2 查看当前源程序
info source
3.4.3 查看堆栈信息
info stack
用这条指令你可以看清楚程序的调用层次关系。
3.4.4 查看当前的参数
info args
3.5 列出源一段源程序 === list
3.5.1 列出某个函数
list FUNCTION
3.5.2 以当前源文件的某行为中间显示一段源程序
list LINENUM
3.5.3 接着前一次继续显示
list
3.5.4 显示前一次之前的源程序
list -
3.5.5 显示另一个文件的一段程序
list FILENAME:FUNCTION 或 listFILENAME:LINENUM
3.6 设置断点 === break
  现在我们将要介绍的也许是最常用和最重要的命令:设置断点。无论何时,只要你的程序已被载入,并且当前没有正在运行,你就能设置,修改,删除断点。设置断点的命令是break。有许多种设置断点的方法。如下:
3.6.1 在函数入口设置断点

如何定位内存泄露?

内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的、大小任意的(内存块的大小可以在程序运行期决定)、使用完后必须显示释放的内存。应用程序一般使用mallocreallocnew等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用freedelete释放该内存块。否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。

C++程序缺乏相应的手段来检测内存信息,只能使用top指令观察进程的动态内存总额。而且程序退出时,我们无法获知任何内存泄漏信息

使用Linux命令回收内存,可以使用pskill两个命令检测内存使用情况和进行回收。在使用超级用户权限时使用命令“ps”,它会列出所有正在运行的程序名称和对应的进程号(PID)。kill命令的工作原理是向Linux操作系统的内核送出一个系统操作信号和程序的进程号(PID

动态链接和静态链接的区别

动态链接是指在生成可执行文件时不将所有程序用到的函数链接到一个文件,因为有许多函数在操作系统带的dll文件中,当程序运行时直接从操作系统中找。 而静态链接就是把所有用到的函数全部链接到exe文件中。
动态链接是只建立一个引用的接口,而真正的代码和数据存放在另外的可执行模块中,在运行时再装入;而静态链接是把所有的代码和数据都复制到本模块中,运行时就不再需要库了。

32位系统一个进程最多有多少堆内存

多线程和多进程的区别(重点面试官最最关心的一个问题,必须从cpu调度,上下文切换,数据共享,多核cup利用率,资源占用,等等各方面回答,然后有一个问题必须会被问到:哪些东西是一个线程私有的?答案中必须包含寄存器,否则悲催)

我们按照多个不同的维度,来看看多进程和多线程的对比(注:都是相对的,不是说一个好得不得了,另一个差的无法忍受)

维度

多进程

多线程

总结

数据共享、同步

数据是分开的:共享复杂,需要用IPC;同步简单

多线程共享进程数据:共享简单;同步复杂

各有优势

内存、CPU

占用内存多,切换复杂,CPU利用率低

占用内存少,切换简单,CPU利用率高

线程占优

创建销毁、切换

创建销毁、切换复杂,速度慢 

创建销毁、切换简单,速度快 

线程占优 

编程调试

编程简单,调试简单

编程复杂,调试复杂

进程占优 

可靠性

进程间不会相互影响 

一个线程挂掉将导致整个进程挂掉

进程占优

分布式 

适应于多核、多机分布;如果一台机器不够,扩展到多台机器比较简单

适应于多核分布

进程占优

然后我们来看下线程和进程间的比较

 

子进程继承父进程的属性:

子线程继承主线程的属性:

实际用户ID,实际组ID,有效用户ID,有效组ID

附加组ID

进程组ID

会话ID

控制终端;

设置用户ID标志和设置组ID标志;

当前工作目录;

根目录;

文件模式创建屏蔽字(umask);

信号屏蔽和安排;

针对任一打开文件描述符的在执行时关闭(close-on-exec)标志;

环境;

连接的共享存储段;

存储映射;

资源限制;

进程中的所有信息对该进程的所有线程都是共享的;

可执行的程序文本;

程序的全局内存;

堆内存;

栈;

文件描述符;

信号的处理是进程中所有线程共享的(注意:如果信号的默认处理是终止该进程那么即是把信号传给某个线程也一样会将进程杀掉);

 

父子进程之间的区别:

子线程特有的:

fork的返回值(=0子进程)

进程ID不同;

两个进程具有不同的父进程ID

子进程的tms_utime,tms_stime,tms_cutime以及tms_ustime均被设置为0

不继承父进程设置的文件锁;

子进程的未处理闹钟被清除;

子进程的未处理信号集设置为空集;

线程ID

一组寄存器值;

栈;

调度优先级和策略;

信号屏蔽字;

errno变量;

线程私有数据;

 


1)
需要频繁创建销毁的优先用线程。
实例:web服务器。来一个建立一个线程,断了就销毁线程。要是用进程,创建和销毁的代价是很难承受的。
2
)需要进行大量计算的优先使用线程。
所谓大量计算,当然就是要消耗很多cpu,切换频繁了,这种情况先线程是最合适的。
实例:图像处理、算法处理
3
)强相关的处理用线程,若相关的处理用进程。
什么叫强相关、弱相关?理论上很难定义,给个简单的例子就明白了。
一般的server需要完成如下任务:消息收发和消息处理。消息收发和消息处理就是弱相关的任务,而消息处理里面可能又分为消息解码、业务处理,这两个任务相对来说相关性就要强多了。因此消息收发和消息处理可以分进程设计,消息解码和业务处理可以分线程设计。
4
)可能扩展到多机分布的用进程,多核分布的用线程。
5
)都满足需求的情况下,用你最熟悉、最拿手的方式。

至于数据共享、同步编程、调试可靠性这几个维度的所谓的复杂、简单应该怎么取舍,只能说:没有明确的选择方法。一般有一个选择原则:如果多进程和多线程都能够满足要求,那么选择你最熟悉、最拿手的那个。

 

一般运行一个程序称为一个进程。

进程可以创建线程,也可以创建进程。

线程是由进程管理的,线程之间、线程和父进程(创建线程的进程)之间可以共享内存变量(需要使用策略的)。

进程之间一般不可以直接共享内存变量,需要使用一些进程间的控制共享内存变量。

如果你使用并行计算,建议使用线程。

 

 

 

进程是个容器或者说资源管理者,有独立的内存地址空间。
线程依赖于它所在的进程,共享进程的资源和内存地址空间。

unix
特别是linux里面,线程与进程接近;windows的进程完全是个容器,线程更轻量级。具体可以了解linux下的fork以及clonewindowscreateprocesscreatethread

 

什么是进程。最直观的就是一个个pid,官方的说法就:进程是程序在计算机上的一次执行活动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值