百度一面凉经

1、Linux内存空间 动态链接库放在哪里

进程内存的分配与回收

创建进程fork()、程序载入execve()、映射文件mmap()、动态内存分配malloc()/brk()等进程相关操作都需要分配内存给进程。不过这时进程申请和获得的还不是实际内存,而是虚拟内存,准确的说是“内存区域”。进程对内存区域的分配最终都会归结到do_mmap()函数上来(brk调用被单独以系统调用实现,不用do_mmap()),内核使用do_mmap()函数创建一个新的线性地址区间。但是说该函数创建了一个新VMA并不非常准确,因为如果创建的地址区间和一个已经存在的地址区间相邻,并且它们具有相同的访问权限的话,那么两个区间将合并为一个。如果不能合并,那么就确实需要创建一个新的VMA了。但无论哪种情况, do_mmap()函数都会将一个地址区间加入到进程的地址空间中--无论是扩展已存在的内存区域还是创建一个新的区域。同样,释放一个内存区域应使用函数do_ummap(),它会销毁对应的内存区域。

2、查看进程状态命令 kill -9什么意思

netstat -ntlp

  -a 显示所有socket,包括正在监听的。  -c 每隔1秒就重新显示一遍,直到用户中断它。  -i 显示所有网络接口的信息,格式同“ifconfig -e”。  -n 以网络IP地址代替名称,显示出网络连接情形。  -r 显示核心路由表,格式同“route -e”。  -t 显示TCP协议的连接情况。  -u 显示UDP协议的连接情况。  -v 显示正在进行的工作。

kill -9 只有第9种信号(SIGKILL)才可以无条件终止进程,其他信号进程都有权利忽略。

3、C++从源文件到可执行文件流程

4、虚函数机制

5、构造函数 静态函数为什么不能是虚函数

虚函数调用是在部分信息下完成工作的机制,允许我们只知道接口而不知道对象的确切类型。 要创建一个对象,你需要知道对象的完整信息。 特别是,你需要知道你想要创建的确切类型。 因此,构造函数不应该被定义为虚函数。因为在调⽤构造函数时,虚表指针并没有在对象的内存空间中,必须要构造函数调用完成后才会形成虚表指针.

  1. 内联函数是编译时展开函数体,所以在此时就需要有实体,而虚函数是运行时才有实体,所以内联函数不可以为虚函数。

  2. 静态成员函数是属于类的,不属于任何一个类的对象,可以通过作用域以及类的对象访问,本身就是一个实体,所以不能定义为虚函数。

6、动态链接库与静态链接库的区别

静态库

当程序与静态库连接时,库中目标文件所含的所有将被程序使用的函数的机器码被 copy 到最终的可执行文件中。这就会导致最终生成的可执行代码量相对变多,相当于编译器将代码补充完整了,优点,这样运行起来相对就快些。不过会有个缺点: 占用磁盘和内存空间. 静态库会被添加到和它连接的每个程序中, 而且这些程序运行时, 都会被加载到内存中. 无形中又多消耗了更多的内存空间。

动态库

与共享库连接的可执行文件只包含它需要的函数的引用表,而不是所有的函数代码,只有在程序执行时, 那些需要的函数代码才被拷贝到内存中。优点,这样就使可执行文件比较小, 节省磁盘空间,更进一步,操作系统使用虚拟内存,使得一份共享库驻留在内存中被多个程序使用,也同时节约了内存。缺点,不过由于运行时要去链接库会花费一定的时间,执行速度相对会慢一些,总的来说静态库是牺牲了空间效率,换取了时间效率,共享库是牺牲了时间效率换取了空间效率,没有好与坏的区别,只看具体需要了。

7、进程线程区别 8、进程线程通信方式 9、fork原理,写时复制过程

fork()系统调用注意点:

通过以上程序我们可以知道:1)fork系统调用之后,父进程和子进程交替执行,并且它们处于不同空间中。

2)fork()函数的一次调用返回2次返回,这个有点抽象难理解,此时二个进程处于独立的空间,它们各自执行者自己的东西,不产生冲突,所以返回2次一次pid ==0,一次pid大于0.而至于是先子进程还是父进程先执行,这没有确切的规定,是随机的.

3)将fork()返回值大于零设置为父进程,这是因为子进程获得父进程的pid相对容易,而父进程获子进程pid叫难,所以在在fork()系统调用中将子进程的pid字节有它自己返回给父进程.

4)forl()的子执行过程在fork()之后并不是从头开始,因为在fork()之前,父进程已经为子进程搭建好了运行环境了.所以字节有效代码处开始.理解了上面四点,相信我们应该对此系统调用一定有较深的了解.

vfork()

  • 1)vfork() 子进程与父进程共享数据段

    2)vfork() 中是子进程先执行,父进程后执行.通常我们都是与exec函数在一起,在主进程中替换进程印象.

10、操作系统虚拟内存机制,如何地址转换 11、TCP三次握手和四次挥手,为什么要3次,2次会出现什么后果,为什么4次,为什么要2MSL

如果采取两次握手,相当于第二次握手结束便建立连接,如果发送SYN的一方不想连接了,也不会有反馈,另一方却一直在等待,浪费了时间。

12、为什么要用滑动窗口,流量控制控制什么

如果发送者发送数据过快,接收者来不及接收,那么就会有分组丢失。为了避免分组丢失,控制发送者的发送速度,使得接收者来得及接收,这就是流量控制。流量控制根本目的是防止分组丢失,它是构成TCP可靠性的一方面。

由滑动窗口协议(连续ARQ协议)实现。滑动窗口协议既保证了分组无差错、有序接收,也实现了流量控制。主要的方式就是接收方返回的 ACK 中会包含自己的接收窗口的大小,并且利用大小来控制发送方的数据发送。

为了避免流量控制引发的死锁,TCP使用了持续计时器。每当发送者收到一个零窗口的应答后就启动该计时器。时间一到便主动发送报文询问接收者的窗口大小。若接收者仍然返回零窗口,则重置该计时器继续等待;若窗口不为0,则表示应答报文丢失了,此时重置发送窗口后开始发送,这样就避免了死锁的产生。

13、拥塞控制用来干什么?几个拥塞控制的算法

拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况.

14、什么情况下执行不用索引(优化器判断代价如果扫描代价比索引小,便不使用索引) 15、mysql怎么看是否用了索引,explain返回的索引类型

对表访问方式,表示MySQL在表中找到所需行的方式,又称“访问类型”。

常用的类型有: ALL、index、range、 ref、eq_ref、const、system、NULL(从左到右,性能从差到好)

ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行 index: Full Index Scan,index与ALL区别为index类型只遍历索引树 range:只检索给定范围的行,使用一个索引来选择行 ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值 eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件 const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。

16、数据库写数据流程,数据直接写到磁盘吗?

17、C++write返回成功,数据是否已经写到磁盘

write函数将数据写到内核便返回,具体的写入是系统内核写入。

18、innoDB索引,用B+树有什么好处,为啥不用平衡二叉树

索引:索引(Index)是帮助数据库高效获取数据的数据结构。

索引是存在于索引文件中,是存在于磁盘中的。因为索引通常是很大的,因此无法一次将全部索引加载到内存当中,因此每次只能从磁盘中读取一个磁盘页的数据到内存中。而这个磁盘的读取的速度较内存中的读取速度而言是差了好几个级别。逻辑结构上的平衡二叉树,其物理实现是数组。然后由于在逻辑结构上相近的节点在物理结构上可能会差很远。因此,每次读取的磁盘页的数据中有许多是用不上的。因此,查找过程中要进行许多次的磁盘读取操作。而适合作为索引的结构应该是尽可能少的执行磁盘IO操作,因为执行磁盘IO操作非常的耗时。因此,平衡二叉树并不适合作为索引结构。

使用红黑树(平衡二叉树)结构的话,每次磁盘预读中的很多数据是用不上的数据。因此,它没能利用好磁盘预读的提供的数据。然后又由于深度大(较B树而言),所以进行的磁盘IO操作更多。

B树的每个节点可以存储多个关键字,它将节点大小设置为磁盘页的大小,充分利用了磁盘预读的功能。每次读取磁盘页时就会读取一整个节点。也正因每个节点存储着非常多个关键字,树的深度就会非常的小。进而要执行的磁盘读取操作次数就会非常少,更多的是在内存中对读取进来的数据进行查找。

B+树的关键字全部存放在叶子节点中,非叶子节点用来做索引,而叶子节点中有一个指针指向一下个叶子节点。做这个优化的目的是为了提高区间访问的性能。而正是这个特性决定了B+树更适合用来存储外部数据。B树必须用中序遍历的方法按序扫库,而B+树直接从叶子结点挨个扫一遍就完了,B+树支持range-query非常方便,而B树不支持。

19、聚集索引和非聚集索引

聚集索引,叶子节点存的是整行数据,直接通过这个聚集索引的键值找到某行。数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的。

非聚集索引,叶子节点存的是字段的值,通过这个非聚集索引的键值找到对应的聚集索引字段的值,再通过聚集索引键值找到表的某行,类似oracle通过键值找到rowid,再通过rowid找到行

innoDB默认通过主键聚集数据,如果没有定义主键,则选择第一个非空的唯一索引,如果没有非空唯一索引,则选择rowid来作为聚集索引

20、二级索引的会存储该行所有的数据吗

21、主从复制 22、了解过redis吗 23、指针引用区别 24、C++四种强制类型转换 25、析构函数一定是虚函数吗

默认为虚函数,不一定为虚函数。

算法:二叉树节点间距离

代码:memcpy

https://blog.csdn.net/enjoymyselflzz/article/details/81165850

1.src和dest所指内存区域不能重叠

2.与strcpy相比,memcpy遇到‘\0’并不会结束,而是一定会拷贝完n个字节

3.memcpy可以拷贝任何数据类型的对象,可以指定拷贝的数据长度

4.如果dest本身就有数据,执行memcpy()后会覆盖原有的数据

5.dest和src都不一定时数组,任意的可读写的空间均可

6.如果要追加数据,则每次执行memcpy后,要将目标数组地址增加到所要追加数据的地址

void *my_memcpy_byte(void *dst, const void *src, int n) {  if (dst == NULL || src == NULL || n <= 0)  return NULL;   char * pdst = (char *)dst;  char * psrc = (char *)src;   if (pdst > psrc && pdst < psrc + n)  {  pdst = pdst + n - 1;  psrc = psrc + n - 1;  while (n--)  *pdst-- = *psrc--;  }  else  {  while (n--)  *pdst++ = *psrc++;  }  return dst; }

代码:strcpy

char * strcpy(char *dst,const char *src) //[1] {  assert(dst != NULL && src != NULL); //[2]  char *ret = dst; //[3]  while ((*dst++=*src++)!='\0'); //[4]  return ret; }


#百度##面经##C++工程师##校招#
全部评论

相关推荐

3 47 评论
分享
牛客网
牛客企业服务