type
status
date
slug
summary
tags
category
icon
password
2024 拼多多后端实习面经
他这个面试这么奇怪,还换部门面试的
📎一面(2024.03.31,已通过)
部门:物流管理
算法题
lc845 数组中的最长山脉(中等)
C++ & Golang
(1)内存泄漏是什么?
Answer:
内存泄漏(Memory Leak)是指已分配的内存未能成功释放回操作系统或内存池,导致该部分内存在未来无法被再次使用的现象。内存泄漏在长时间运行的程序中尤为严重,因为随着时间的推移,可用内存会越来越少,最终可能导致程序运行缓慢或异常终止。
内存泄漏的原因
内存泄漏可以由多种原因引起,常见的有:
- 未释放内存:程序分配了内存给某个对象,但在不再使用该对象后,未正确释放或删除其占用的内存。
- 循环引用:在一些具有垃圾回收机制的语言中(如JavaScript、Python),两个或多个对象相互引用,但它们不再被其他活跃的对象引用。这种情况下,垃圾回收器可能无法识别这些对象为垃圾,导致它们占用的内存不被释放。
- 静态集合类的滥用:在一些编程语言中,静态集合类(如静态列表、哈希表等)存储了对象的引用,如果不显式移除,即使对象不再需要,它们也会一直占用内存。
- 缓存机制的错误使用:错误地管理缓存,比如缓存过多数据而没有相应的淘汰机制,也会导致内存泄漏。
(2)除了去排查代码,还有什么办法来检测内存泄漏的情况?
Answer:
在Go语言开发中,管理和检测内存泄漏也是一个重要的任务。由于Go的运行时包括一个垃圾回收器(GC),它可以帮助减少内存泄漏的可能性,但是依然存在因错误使用或者不当的资源管理导致的内存泄漏情况。Go提供了一些工具和库来帮助检测和分析内存泄漏:
pprof
pprof
是Go语言标准库中的一个强大工具,用于收集和分析性能数据。它可以生成堆内存的剖析报告,帮助开发者找到内存分配的热点。使用pprof
,你可以通过HTTP服务器动态获取程序的性能分析数据,或者将分析数据导出并使用go tool pprof
命令行工具进行分析。要使用
pprof
检测内存泄漏,可以这样做:- 导入
net/http/pprof
包启动pprof分析HTTP服务器。
- 在程序运行过程中,通过访问
http://localhost:端口/debug/pprof/heap
获取堆内存的剖析报告。
- 使用
go tool pprof
工具下载和分析堆内存剖析数据,寻找内存分配的热点和潜在的内存泄漏。
除了Go标准库中的工具外,还有一些第三方工具和库可以帮助检测内存泄漏,例如:
- go-leak:一个专门用于检测goroutine泄漏的库。
- memguard:一个安全的内存管理库,可以帮助防止内存泄漏和其他内存相关的安全问题。
使用这些工具和实践可以帮助Go开发者有效地管理内存使用和检测潜在的内存泄漏问题。
(3)多态有什么种类?
(4)多态的目的是什么?
(5)go实现一个死锁怎么弄?
Answer:
这段代码试图从一个未缓冲的channel
ch
中接收数据,但是没有任何数据被发送到这个channel。由于Go的运行时能够检测到这种情况(当所有goroutine都无法继续运行时),它会报告一个死锁错误:设计模式
(1)给了一段代码,看看有什么问题,要怎么修改?(很多if,应该是拓展问题,但我不懂。。)
(2)我们如果疯狂对需求,一直加代码,可能后期就会导致代码非常臃肿无法维护,这个时候我们要怎么办?(提到了git rebase,他居然说确实可行,我真乱说的)
Mysql
(1)索引下推是什么?
(2)为什么要用自增id?
(3)随机id会导致B+树什么问题?
Answer:
我们在建表的时候,都会默认将主键索引设置为自增的,具体为什么要这样做呢?又什么好处?
InnoDB 创建主键索引默认为聚簇索引,数据被存放在了 B+Tree 的叶子节点上。也就是说,同一个叶子节点内的各个数据是按主键顺序存放的,因此,每当有一条新的数据插入时,数据库会根据主键将其插入到对应的叶子节点中。
如果我们使用自增主键,那么每次插入的新数据就会按顺序添加到当前索引节点的位置,不需要移动已有的数据,当页面写满,就会自动开辟一个新页面。因为每次插入一条新记录,都是追加操作,不需要重新移动数据,因此这种插入数据的方法效率非常高。
如果我们使用非自增主键,由于每次插入主键的索引值都是随机的,因此每次插入新的数据时,就可能会插入到现有数据页中间的某个位置,这将不得不移动其它数据来满足新数据的插入,甚至需要从一个页面复制数据到另外一个页面,我们通常将这种情况称为页分裂。页分裂还有可能会造成大量的内存碎片,导致索引结构不紧凑,从而影响查询效率。
(4)mysql的数据页是什么?
(5)mysql读写后的脏页,是怎么处理的?(buffer pool的刷新策略)
分布式
(1)mysql主从复制是怎么实现的?(binlog)
(2)主从结构是怎么分摊分布式压力的?
(3)如果要同时修改多张表的字段,它怎么保证主库和从库的一致性?(面试官说是分布式事务,然后说没做过不知道也正常)
然后就问项目去了。。。确实有点难,问到了很多刚好不会的点。。。
📎二面(2024.4.9,已通过)
部门:拼多多搜广推
一开始问项目,也没啥好说的
Golang
(1)golang里面的slice底层是什么?函数传递的时候是值传递还是引用传递?
(2)C++里面有没有像slice类似的结构?(我说vector他说不太像,因为slice还有len的特性)
(3)golang的map遍历为什么是无序的?
(4)为什么golang的map遍历要设置为无序?这是出于什么样的设计理念?
Answer:
map 在扩容后,会发生 key 的搬迁,原来落在同一个 bucket 中的 key,搬迁后,有些 key 就要远走高飞了(bucket 序号加上了 2^B)。而遍历的过程,就是按顺序遍历 bucket,同时按顺序遍历 bucket 中的 key。搬迁后,key 的位置发生了重大的变化,有些 key 飞上高枝,有些 key 则原地不动。这样,遍历 map 的结果就不可能按原来的顺序了。
当然,如果我就一个 hard code 的 map,我也不会向 map 进行插入删除的操作,按理说每次遍历这样的 map 都会返回一个固定顺序的 key/value 序列吧。的确是这样,但是 Go 杜绝了这种做法,因为这样会给新手程序员带来误解,以为这是一定会发生的事情,在某些情况下,可能会酿成大错。
当然,Go 做得更绝,当我们在遍历 map 时,并不是固定地从 0 号 bucket 开始遍历,每次都是从一个随机值序号的 bucket 开始遍历,并且是从这个 bucket 的一个随机序号的 cell 开始遍历。这样,即使你是一个写死的 map,仅仅只是遍历它,也不太可能会返回一个固定序列的 key/value 对了。
多说一句,“迭代 map 的结果是无序的”这个特性是从 go 1.0 开始加入的。
算法题
lc 236 二叉树的最近公共祖先(中等)
lc 416 分割等和子集(中等) → 改造成4等分,不过无所谓是一样的
📎三面(2024.4.18,已通过)
部门:物流管理
先跟我聊什么人生规划,为什么去ntu啊,工作了后面几年怎么规划?选开发or算法balabala
后面聊完了讲了个项目,感觉他还算认可
mysql
(1)msyql可重复读是怎么实现的?
算法题
感觉是一道中等偏上的题,类似于 lc207 课程表(中等),不过比它难一点
有N个工作任务,各个工作之间存在依赖关系,例如必须先完成A工作,才能去执行B工作,现在给出每个工作的执行时间,在零时刻时,你收到了全部的工作任务,问你怎么规划,才能使得你完成所有任务的时候,每个任务的平均等待时间最短。可能会有多种不同的答案,请你返回字典序最小的那一个。
第一行输入N,M,表示有N个工作任务以及M个依赖关系
第二行输入N个整数,表示每个工作任务所需的时间
第三行开始,有M行输入,每一行两个整数A,B,表示工作B依赖于工作A
示例输入:
示例输出:
Answer:
这题很明显的拓扑排序+贪心,可以用类似于操作系统里面的“短作业优先”方法,来实现最短平均时间的效果,于是我们可以用一个优先队列来完成这个任务
📎hr面(2024.4.28)
- 作者:Kasyn
- 链接:https://kasyn.blog/article/intern-2024-pdd
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章