【小米】Linux 实习生

下午不准备去图书馆自习来着,中午就狠狠地多睡了一个小时,三点起床靠在椅子上剥柚子,太爽了,这秋天的下午。"邮件:小米公司邀请你预约面试时间"..........

我擦,投了一个月了,认真准备的时候没有面试,现在躺了,来了面了~~~预约到了第二天下午,怎么办呢,考不考算法哇,考不考设计模式哇,考不考命令哇.....炸裂哇~

还能说什么呢,机会不是每次都有,还能怎么着,快学,赶紧穿好衣服去自习室复习复习,开卷


开面!

「面试官」自我介绍吧,别愣着了

「朱小哥」好的哥....

「面试官」说说你的项目背景,自己做的吗

「朱小哥」不是我做的你做的吗?这就是google的tcmalloc的mini版...

「面试官」malloc函数有什么问题呢,为什么需要改进,你的tcmalloc如何解决的

「朱小哥」主要就是针对多线程环境下带来的锁竞争的问题,现代很多的开发环境都是多核多线程,在申请内存的场景下,必然存在激烈的锁竞争问题。那malloc可不就不行了

tcmalloc针对锁竞争这里采用的是,开始吟唱:

既然想要解决多线程环境下存在激烈的锁竞争的问题,就得需要加锁吧,可是如果加的锁粒度太大,是非常影响效率的,所以要想尽可能的不加锁或者少加锁的话,再结合内存池的这个思路,那我就可以实现一个分层的逻辑。

可以做一个多层架构,每一层针对不同大小的内存分配请求使用不同的方法。这种灵活性有助于提高内存的利用率和性能。

  • 每一个ThreadCache是线程独有的,这个地方不需要加锁。我还使用到了一种TLS技术,线程本地缓存,通过它我还可以在第一层就不需要加锁,
  • CentralCache层只有当多个线程同时访问central cache的同一个桶时才会存在锁竞争,如果是多个线程同时访问central cache的不同桶就不会存在锁竞争。
  • central cache的多个桶就可能同时向page cache申请内存的,所以page cache也是存在线程安全问题的,因此在访问page cache时也必须要加锁。但是在page cache这里我们不能使用桶锁,因为当central cache向page cache申请内存时,page cache可能会将其他桶当中大页的span切小后再给central cache。

「面试官」threadcache初识的内存是怎么拿到的,你是怎么拿到的threadcache的

「朱小哥」threadcache是怎么拿到内存的?从对应的哈希桶中去获取哇!第一次申请当然哈希桶中啥也没有,你得去向下一层要,下一层中心缓存也没有,就问PageCache要,PageCache没有就会向堆申请128页的内存

「面试官」PageCache是如何解决内存碎片的问题的

「朱小哥」内碎片是设计的问题,解决不了,外碎片是一些空闲的连续内存区域太小,这些内存空间不连续,以至于合计的内存足够,但是不能满足一些的内存分配申请需求。

关于如何解决外部碎片,听好了!

  1. 采用一种各层遵守的规范,就是将不同大小的内存块分为不同的大小类别,每个大小类别包含一组相似大小的内存块。这样可以更有效地分配和管理内存,减少了内存碎片。
  2. Thread-Caching 层维护了每个线程的本地内存缓存,这意味着内存块通常在同一个线程内进行分配和释放。这种局部性有助于减少内存碎片,因为同一个线程通常会分配和释放相似大小的内存块,从而减少了碎片化的可能性。
  3. 对于不用的内存,也有必要来回收,实现了内存块的合并机制,可以合并相邻的空闲内存块,从而减少内存碎片。当内存块被释放时,tcmalloc会尝试合并相邻的空闲块,以创建更大的可用内存块,提高内存的利用率。
  4. 如果central cache释放回一个span,则依次寻找span的前后page id的没有在使用的空闲span,看是否可以合并,如果合并继续向前寻找。这样就可以将切小的内存合并收缩成大的span,减少内存碎片。

「面试官」PageCache这里是如何合并内存的呢

「朱小哥」......

「面试官」你到底会不会啊

「朱小哥」忘了忘了

「面试官」噗~~~~,给你个双向链表,你有三个节点,a b c 如何删除节点b,说说操作步骤

「朱小哥」小意思

「面试官」常见的进程间通信的方式

「朱小哥」匿名管道、命令管道、消息队列、共享内存、信号、信号量、socket,你想让我说说哪个~

「面试官」说说进程间通信中的socket通信吧,使用socket进行俩个主机通信的步骤

「朱小哥」王德发!!!选了个最不熟悉的,好你......Socket 实际上不仅用于不同的主机进程间通信,还可以用于本地主机进程间通信,可根据创建 Socket 的类型不同,分为三种常见的通信方式,一个是基于 TCP 协议的通信方式,一个是基于 UDP 协议的通信方式,一个是本地进程间通信方式。

创建Socket:

通信的第一步是创建一个Socket对象,它充当通信的端点。使用socket函数创建一个Socket。

绑定Socket:

为了让Socket能够在网络上被其他计算机访问,需要将其绑定到一个IP地址和端口号。bind函数用于绑定Socket。

监听(对于服务器):

如果你正在编写服务器应用程序,需要使用listen函数来等待客户端的连接请求。

接受连接(对于服务器):

当客户端尝试连接到服务器时,服务器使用accept函数来接受客户端的连接请求,并创建一个新的Socket来处理与该客户端的通信。

建立连接(对于客户端):

客户端使用connect函数来连接到服务器的Socket。

发送数据:

使用send函数来将数据从一个Socket发送到另一个Socket。

接收数据:

使用recv函数来从一个Socket接收数据。

关闭Socket:

当通信结束时,使用close函数来关闭Socket连接。对于服务器端,还需要关闭原始的监听Socket。

这是Socket通信的基本流程。可以使用socket、bind、listen、accept、send、recv和close等系统调用函数来执行这些操作。

「面试官」C++中的默认构造函数有哪些,移动构造呢

「朱小哥」无参构造、一般构造、赋值运算符重载、拷贝构造函数、移动构造(忘了)

「面试官」你给我写一个拷贝构造,什么场景使用拷贝构造

「朱小哥」厚礼蟹!!!拷贝构造怎么写!!!

「面试官」这都不会,

「朱小哥」...

「面试官」拷贝构造是浅拷贝还是深拷贝,说说深浅拷贝的区别

「朱小哥」软了...,肯定是深拷贝哇

  1. 浅拷贝, 又叫做值拷贝. 将源对象的值拷贝到目标对象中去. 本质上来说源对象和目标对象共用同一份实体, 只是所引用的变量名不同, 指向的地址是相同的.
  • 浅拷贝中, 如果目标对象的值修改了, 则源对象的值也会相应改变
  1. 深拷贝, 拷贝的时候先开辟出和源对象大小一样的空间, 然后将源对象里的内容拷贝到目标对象当中去, 这样俩个指针指向了不同的内存位置, 并且里面的值是一样的.
  • 深拷贝的情况下, 不会出现重复释放同一块内存的错误
  • 深拷贝的实现: 拷贝构造和赋值运算符重载实现

「面试官」指针和引用的区别

「朱小哥」简单哇

  1. 指针是一个实体,需要分配内存空间,引用只是个别名,不需要内存空间
  2. 指针在定义的时候不一定要初始化,引用必须初始化,并且不能改变所引用的变量
  3. 指针可以时空指针,引用不能是空
  4. 有多级指针,没有多级引用
  5. 引用的底层是指针

「面试官」一个类中是有成员变量和有构造函数和析构函数的,这些函数会不会占用内存空间呢

「朱小哥」我觉得你说的有问题,成员函数是存放在代码段的,当然占用内存,但是类对象的大小只包含成员变量,不包含成员函数,会将类对象的地址传递给this指针,当调用一个对象的非静态成员函数时, 系统会把该对象的起始地址赋给成员函数的 this 指针, 另外,静态成员函数不属于任何一个对象, 所以静态成员函数没有 this 指针, 既然它没有指向某一对象, 也就无法对一个对象中的非静态成员进行访问

「面试官」memcpy和memmove使用过吗,具体说说

「朱小哥」不会

memcpy 函数用于从一个内存区域复制一定数量的字节到另一个内存区域。它将源内存区域的内容按顺序复制到目标内存区域,无论它们是否重叠。

void *memcpy(void *dest, const void *src, size_t n);

memmove 函数也用于从一个内存区域复制一定数量的字节到另一个内存区域,但与 memcpy 不同,它会处理重叠的内存区域。memmove 会检查内存区域是否重叠,如果重叠,通过使用一个临时缓冲区,将源内存区域的数据复制到这个缓冲区,然后再将缓冲区的数据复制到目标内存区域。这种方法确保数据的正确复制而不会破坏原始数据。

void *memmove(void *dest, const void *src, size_t n);

由于需要使用额外的内存来存储临时缓冲区,所以 memmove 可能比 memcpy 性能稍差,但它保证了数据的完整性和正确性。

「面试官」呼~,反问吧,有什么就问

「朱小哥」组是做什么的

「面试官」巴拉巴拉........

「朱小哥」我可以进入二面吗

「面试官」别问,问就是回家等消息~,怎么说呢,回答还凑活,指针和引用是背八股的吧,简直和网上回答是一样,你不得理解理解?不能光背哇,背还背不熟.....拷贝构造都不会写就有点太离谱了

「朱小哥」面试结束我学还不行嘛,找个实习太难了

相关推荐
wdxylb2 小时前
云原生俱乐部-shell知识点归纳(1)
linux·云原生
飞雪20073 小时前
Alibaba Cloud Linux 3 在 Apple M 芯片 Mac 的 VMware Fusion 上部署的完整密码重置教程(二)
linux·macos·阿里云·vmware·虚拟机·aliyun·alibaba cloud
路溪非溪3 小时前
关于Linux内核中头文件问题相关总结
linux
Lovyk6 小时前
Linux 正则表达式
linux·运维
Fireworkitte7 小时前
Ubuntu、CentOS、AlmaLinux 9.5的 rc.local实现 开机启动
linux·ubuntu·centos
sword devil9007 小时前
ubuntu常见问题汇总
linux·ubuntu
ac.char7 小时前
在CentOS系统中查询已删除但仍占用磁盘空间的文件
linux·运维·centos
淮北也生橘129 小时前
Linux的ALSA音频框架学习笔记
linux·笔记·学习
华强笔记12 小时前
Linux内存管理系统性总结
linux·运维·网络
十五年专注C++开发12 小时前
CMake进阶: CMake Modules---简化CMake配置的利器
linux·c++·windows·cmake·自动化构建