高频高频

1.C++面向对象的三种特性?

封装:可以隐藏细节,使得代码模块化。把数据和方法封装成抽象的类,只让可信的类或对象操作,对不可信的隐藏。
继承:它可以使用现有类的所有功能,并在进行扩展。
多态:父类的指针指向子类的对象。

多态的实现方式?覆盖(重写)和重载(其实不是多态,静态的)。

2.构造函数可以是虚函数么?

构造函数不可以是虚函数,因为含有虚函数的类中有虚表指针,指向虚函数表。当定义一个对象的时候,首先会分配对象内存空间,然后调用构造函数来初始化对象。虚表指针就是在构造函数中进行初始化的。因为执行虚函数需要通过虚表指针来调用。如果构造函数为虚函数的话,就会陷入先有鸡还是先有蛋的循环中。

3.C++的析构函数可以是虚函数么?

将可能会被继承的父类的析构函数析构函数设置为虚函数,可以保证当父类指针指向子类对象时,释放父类指针时可以释放掉子类空间,防止内存泄漏。
C++默认析构函数不是虚函数,因为虚函数需要额外的虚函数表和虚表指针,占用额外内存。对于不会被继承的类来说,浪费内存。

4.C++如何实现多态?虚表指针是什么时候被初始化的?实例化一个对象需要那几个阶段?(三个)

多态使用虚函数来实现,结合动态绑定。当c++编译器在编译的时候,发现父类的函数是虚函数,就会采用晚绑定技术。在运行时,依据对象的类型来确认调用的是哪一个函数,这种能力就叫做c++的多态性。
虚表指针是由构造函数初始化的
无继承时: 1、分配内存 2、初始化列表之前赋值虚表指针 3、列表初始化 4、执行构造函数体
有继承时: 1、分配内存 2、基类构造过程(按照无继承来) 3、初始化子类虚表指针 4、子类列表初始化 5、执行子类构造函数体

5.inline和宏定义的区别?

inline是指嵌入代码,在调用函数的地方不跳转,直接把代码写到那。
inline一般只用于如下情况:
(1)一个函数不断被重复调用。
(2)函数只有简单的几行,且函数不包含for、while、switch语句。
宏是在代码处不加任何验证的简单替代,而内联函数是将代码直接插入调用处,而减少了普通函数调用时的资源消耗。
1.内联函数的调用是传参,宏定义只是简单的文本替换
2.内联函数可以在程序运行时调用,宏定义是在程序编译进行
3.内联函数有类型检测更加的安全,宏定义没有类型检测
4.内联函数在运行时可调试,宏定义不可以
5.内联函数可以访问类的成员变量,宏不可以
6.类中的成员函数是默认的内联函数

6.malloc底层实现?

Linux维护一个break指针,这个指针指向堆空间的某个地址。从堆起始地址到break之间的地址空间为映射好的,可以供进程访问;而从break往上,是未映射的地址空间,如果访问这段空间则程序会报错。我们用malloc进行内存分配就是从break往上进行的。 获得了break指针的位置也就得到了堆内存申请的起始地址 malloc实际上是将可用空间用一个空闲链表连接起来,若用户申请空间,就遍历该链表,找到第一个满足条件的空闲块,将其进行拆分,返回合适大小的空间给用户,将剩下的部分链接到链表中。当调用free释放空间时,会把这块空间连接到空闲链表上。到最后,该空闲链就会被切成很多的小内存块,一旦用户申请一块较大的空间,空闲链中的空间大小都无法满足需求,malloc会申请延时,对空闲链表进行检查,内存重新整理,把相邻的小片段合并成大的空闲块。

1.当开辟的空间小于128k时,调用brk()函数,malloc的底层实现是系统调用函数brk(),其主要移动指针_enddata(Linux 地址空间中堆段的末尾地址)来开辟空间;
执行malloc(30K),malloc函数会调用brk系统调用,将_edata指针往高地址推30K,就完成虚拟内存分配。
  你可能会问:难道这样就完成内存分配了?
  事实是:_edata+30K只是完成虚拟地址的分配,A这块内存现在还是没有物理页与之对应的,等到进程第一次读写A这块内存的时候,发生缺页中断,这个时候,内核才分配A这块内存对应的物理页。也就是说,如果用malloc分配了A这块内容,然后从来不访问它,那么,A对应的物理页是不会被分配的。

2.当开辟的空间大于128k时,mmap()系统调用函数来在虚拟地址空间中(堆和栈中间,称为文件映射区域的地方)找一块空间来开辟。
进程调用C=malloc(200K)后,此时并不会推_edata指针了,而是利用mmap系统调用,从堆和栈的中间分配一块虚拟内存。这样子做主要是因为:
  brk分配的内存需要等到高地址内存释放以后才能释放(例如,在B释放之前,A是不可能释放的,因为只有一个_edata 指针,这就是内存碎片产生的原因,什么时候紧缩看下面),而mmap分配的内存可以单独释放。

7.Linux虚拟地址空间布局?

在多任务操作系统中,每个进程都运行在属于自己的虚拟地址空间中。在32位模式下它是一个4GB的内存地址快。在linux系统中,内核进程和用户进程所占的虚拟内存比例是1:3,windows系统是2:2。
虚拟地址通过页表映射到物理内存,页表由操作系统维护并被处理器引用。

用户进程部分存储内容:代码段(可执行代码、字符串常量、只读变量),数据段(已初始化且初始值非0的全局和静态变量),.bss段(未初始化或初始化为0的全局和静态变量),堆(动态分配的内存),,mmap(内存映射区,内核将文件的内容直接映射到内存),栈(局部变量,函数参数,返回地址等)

mmap(内存映射段):内核将文件的内容直接映射到内存。任何应用程序都可以通过linux的mmap()系统调用请求这种映射。内存映射是一种方便高效的文件I/O方式,所以它被用来加载动态库。

栈和堆的区别:
1.管理方式:栈是编译器自动管理,堆空间的申请和释放由程序员控制。
2.空间大小:栈是向低地址扩展的数据结构,是一块连续的内存区域。通常为几M。堆是向高地址扩展的数据结构,是不连续的内存区域,因为系统是用链表来存储空闲内存地址的。
3.是否产生碎片:栈不存在;但频繁地malloc/free会造成内存空间的不连续,造成大量的碎片,使程序效率降低。

8.close_wait状态?

在被动关闭连接情况下,已经收到了FIN,但是还没有发送自己的FIN,连接就会处于close_wait状态。
出现大量close_wait的现象,主要原因是某种情况下对方关闭了socket连接,但是我方忙于读或写,没有关闭连接。

解决方法:
基本思想就是要检测出对方已经关闭的socket,然后关闭它。
1.代码层面做到第一:使用完socket调用close方法;第二:socket读控制,当读取的长度为0时(读到结尾),立即close;第三:如果read返回-1,出现错误,检查error返回码,有三种情况:INTR(被中断,可以继续读取),WOULDBLOCK(表示当前socket_fd文件描述符是非阻塞的,但是现在被阻塞了),AGAIN(表示现在没有数据稍后重新读取)。如果不是AGAIN,立即close
2.可以设置TCP的连接时长keep_alive_time还有tcp监控连接的频率以及连接没有活动多长时间被迫断开连接

查看主机tcp目前的状态
netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值