写点什么

裁员还能有天花板?

作者:王中阳Go
  • 2024-08-05
    北京
  • 本文字数:3951 字

    阅读完需:约 13 分钟

裁员还能有天花板?

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家:点击跳转到网站,对人工智能感兴趣的小伙伴可以点进去看看。


这个事是真有意思:


有网友爆料苏州 X 能开始新一批裁员,裁员规模涉及上千人。


乍一听感叹真难呐,这个大公司又要进行裁员了,结果继续往后面看:赔偿刷新了外企裁员的天花板——无固定合同期限 N+12 或是 2N+12


大家知道这是什么概念吗?


有个员工透露,他的月工资是 7 千元到 1 万元,如今拿到约 25 万元的补偿,他有个同事在这边工作 30 年,最终拿到 150 余万元的补偿。


该说不说有些企业确实实在,回顾之前三 X 裁员也是以员工为主,某些企业 pua 倒是在行,福利待遇却不见得好。


对于这件事你怎么看,欢迎在评论区留言~


下面接着分享粉丝投稿的北京好未来的面经详解,希望对你有帮助:

北京好未来

面试纪要

  1. 自我介绍

  2. 被问了项目中使用的开发框架

3. 切片和数组的区别:

  • 数组的长度是固定的,在声明时就已经确定;切片的长度是可变的,可以动态增加或减少元素数量。

  • 数组是值类型,将一个数组赋值给另一个变量时会复制整个数组;切片是引用类型,赋值时只是复制了切片的引用。

  • 数组的长度是其类型的一部分,不同长度的数组属于不同类型;切片没有这个限制。

4. 切片的扩容机制:

1.7 版本:如果当前容量小于 1024,则判断所需容量是否大于原来容量 2 倍,如果大于,当前容量加上所需容量;否则当前容量乘 2。


如果当前容量大于 1024,则每次按照 1.25 倍速度递增容量,也就是每次加上 cap/4。


1.8 版本:Go1.18 不再以 1024 为临界点,而是设定了一个值为 256 的threshold,以 256 为临界点;超过 256,不再是每次扩容 1/4,而是每次增加(旧容量+3*256)/4;


  1. 当新切片需要的容量 cap 大于两倍扩容的容量,则直接按照新切片需要的容量扩容;

  2. 当原 slice 容量 < threshold 的时候,新 slice 容量变成原来的 2 倍;

  3. 当原 slice 容量 > threshold,进入一个循环,每次容量增加(旧容量+3*threshold)/4。

5. 如何创建一个通道?怎么创建 + 有缓冲通道 + 无缓冲通道 + 底层结构

  • 无缓冲通道:ch := make(chan int)

  • 有缓冲通道:ch := make(chan int, 5)通道的底层结构是一个包含数据存储区域、发送和接收操作的等待队列等部分的结构体。

6. GC(垃圾回收)?

垃圾回收机制是 Go 一大特(nan)色(dian)。Go1.3 采用标记清除法, Go1.5 采用三色标记法,Go1.8 采用三色标记法+混合写屏障


标记清除法


分为两个阶段:标记和清除


标记阶段:从根对象出发寻找并标记所有存活的对象。


清除阶段:遍历堆中的对象,回收未标记的对象,并加入空闲链表。


缺点是需要暂停程序 STW(stop the world)。


三色标记法


将对象标记为白色,灰色或黑色。


白色:不确定对象(默认色);黑色:存活对象。灰色:存活对象,子对象待处理。


标记开始时,先将所有对象加入白色集合(需要 STW)。首先将根对象标记为灰色,然后将一个对象从灰色集合取出,遍历其子对象,放入灰色集合。同时将取出的对象放入黑色集合,直到灰色集合为空。最后的白色集合对象就是需要清理的对象。


这种方法有一个缺陷,如果对象的引用被用户修改了,那么之前的标记就无效了。因此 Go 采用了写屏障技术,当对象新增或者更新会将其着色为灰色。


一次完整的 GC 分为四个阶段:


  1. 准备标记(需要 STW),开启写屏障。

  2. 开始标记

  3. 标记结束(STW),关闭写屏障

  4. /清理(并发)


基于插入写屏障和删除写屏障在结束时需要 STW 来重新扫描栈,带来性能瓶颈。混合写屏障分为以下四步:


  1. GC 开始时,将栈上的全部对象标记为黑色(不需要二次扫描,无需 STW);

  2. GC 期间,任何栈上创建的新对象均为黑色

  3. 被删除引用的对象标记为灰色

  4. 被添加引用的对象标记为灰色


总而言之就是确保黑色对象不能引用白色对象,这个改进直接使得 GC 时间从 2s 降低到 2us。

7. 什么是内存泄漏?

在 Go 中内存泄露分为暂时性内存泄露和永久性内存泄露。


暂时性内存泄露


  • 获取长字符串中的一段导致长字符串未释放

  • 获取长 slice 中的一段导致长 slice 未释放

  • 在长 slice 新建 slice 导致泄漏


获取长 slice 中的一段导致长 slice 未释放:

  • 当从一个长 slice 中获取一段子 slice 时,如果没有正确处理,子 slice 可能会持有对原长 slice 的引用,导致原长 slice 无法被释放。

  • 这种情况下,子 slice 会持有原长 slice 的底层数组的引用,即使子 slice 被丢弃,原长 slice 的底层数组也无法被释放,造成内存泄漏。

  • 避免内存泄漏的方法是使用copy函数将子 slice 复制到一个新的 slice 中,而不是直接引用原长 slice。

在长 slice 新建 slice 导致泄漏

  1. 当在一个长 slice 上再次使用切片操作创建一个新的 slice 时,新的 slice 会共享原长 slice 的底层数组,导致原长 slice 无法被释放。

  2. 这种情况下,新的 slice 会持有原长 slice 的底层数组的引用,即使新的 slice 被丢弃,原长 slice 的底层数组也无法被释放,造成内存泄漏。

  3. 避免内存泄漏的方法是使用copy函数将新的 slice 复制到一个新的 slice 中,而不是直接引用原长 slice。

为避免这两种情况下的内存泄漏,需要注意在处理 slice 时避免共享底层数组的引用,而是使用copy函数创建新的 slice。

确保在不需要使用的时候及时释放不再需要的内存,避免长期持有对底层数组的引用。

同时,合理使用defer语句、关闭资源、避免循环引用等方法也有助于避免内存泄漏的发生。


string 相比切片少了一个容量的 cap 字段,可以把 string 当成一个只读的切片类型。获取长 string 或者切片中的一段内容,由于新生成的对象和老的 string 或者切片共用一个内存空间,会导致老的 string 和切片资源暂时得不到释放,造成短暂的内存泄漏.


永久性内存泄露


  • goroutine 永久阻塞而导致泄漏

  • time.Ticker 未关闭导致泄漏

  • 不正确使用 Finalizer(Go 版本的析构函数)导致泄漏

8. 避免和解决内存泄漏的方式:

  • 及时释放不再使用的资源,如手动释放内存、关闭文件描述符、取消订阅事件等。

  • 使用智能指针或具有自动内存管理功能的语言特性。

  • 进行内存泄漏检测工具的使用,定期检查和分析内存使用情况。

9. InnoDB 引擎和 MyISAM 引擎的区别:

  • 事务支持:InnoDB 支持事务,MyISAM 不支持。

  • 锁机制:InnoDB 支持行级锁,MyISAM 支持表级锁。

  • 数据完整性:InnoDB 保证数据的完整性和一致性,MyISAM 相对较弱。

  • 崩溃恢复:InnoDB 具有较好的崩溃恢复能力,MyISAM 较差。

  • 性能:MyISAM 在读取数据时性能较高,尤其在大量读取操作时;InnoDB 在写入和并发操作时性能较好。

10. 索引多的后果及索引的优缺点:

优点:


  • 提高数据查询速度,快速定位所需数据。

  • 可以保证数据的唯一性,约束数据的完整性。


缺点:


  • 增加数据插入、更新和删除的时间成本,因为每次操作都需要更新索引。

  • 过多的索引会增加存储空间的消耗。

11. Redis 的持久化方式:

RDB 持久化(全量备份)


RDB 持久化是指在指定时间间隔内将内存中的数据集快照写入磁盘。实际上 fork 子线程,先将数据集写入临时文件,写入成功后,在替换之前的文件,用二进制压缩文件,RDB 是 Redis 默认的持久化方式,会在对应目录下生产一个 dump.rdb 文件,重启会通过加载 dump.rdb 文件恢复数据


RDB 优点:


  1. 方便持久化:只有一个dump.rdb文件;

  2. 容灾性好:一个文件可以保存到安全的磁盘;

  3. 性能好:fork 子线程来完成写操作,主线程继续处理命令;

  4. 效率高:如何数据集偏大,RDB 启动效率比 AOF 高


RDB 缺点:


  1. 数据安全性低:因为 RDB 是每隔一段时间进行持久化,可能会造成数据丢失。

  2. 由于 RDB 是通过 fork 子线程协助完成数据持久化工作的,因此如果数据集较大时,可能会导致整个服务停止服务几百毫秒,甚至一分钟。


AOF 持久化(增量备份)AOF 持久化是以日志的形式记录记录每一个增删操作然后追加到文件中。AOF 的出现是为了弥补 RDB 备份的不足(数据不一致性)。


与 RDB 持久化相比,AOF 的持久化实时性更好。


**AOF 的备份策略:**Redis 的配置文件中存在三种不同的 AOF 持久化方式:


  1. appendfsync always:每次有数据修改发生时都会同步。

  2. appendfsync everysec:每秒同步一次

  3. appendsync no:让操作系统决定何时进行同步。


AOF 优点:


  1. AOF 实时性哈好,数据安全性更高;

  2. AOF 通过 append 模式写文件,即使中途服务器宕机,也可以通过redis-check-aof工具解决数据一致性问题。

  3. AOF 机制的 rewrite 模式(文件过大会对命令进行合并重写),可以删除其中某些命令(比如误操作的命令)


AOF 缺点:


  1. AOF 文件比 RDB 文件大,且恢复慢;

  2. 根据同步策略的不同,AOF 在运行效率上往往会慢于 RDB。


两者结合


将 RDB 和 AOF 合体使用,这个方法是在 Redis 4.0 提出的,该方法叫混合使用 AOF 日志和内存快照,也叫混合持久化。


混合持久化工作在 AOF 日志重写过程。


当开启了混合持久化时,在 AOF 重写日志时,fork 出来的重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 AOF 文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。


也就是说,使用了混合持久化,AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据。


这样的好处在于,重启 Redis 加载数据的时候,由于前半部分是 RDB 内容,这样加载的时候速度会很快。


加载完 RDB 的内容后,才会加载后半部分的 AOF 内容,这里的内容是 Redis 后台子进程重写 AOF 期间,主线程处理的操作命令,可以使得数据更少的丢失。

12. Redis 过期淘汰策略:

  • volatile-lru:从设置了过期时间的键中,移除最近最少使用的键。

  • volatile-ttl:从设置了过期时间的键中,移除即将过期的键。

  • volatile-random:从设置了过期时间的键中,随机移除键。

  • allkeys-lru:从所有键中,移除最近最少使用的键。

  • allkeys-random:从所有键中,随机移除键。

  • noeviction:不进行淘汰,当内存使用达到上限时,新的写入操作会报错。

欢迎关注 ❤

我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。


没准能让你能刷到自己意向公司的最新面试题呢。


感兴趣的朋友们可以加我微信:wangzhongyang2024,备注:infoq 面试群。

用户头像

王中阳Go

关注

靠敲代码在北京买房的程序员 2022-10-09 加入

【微信】wangzhongyang1993【公众号】程序员升职加薪之旅【成就】InfoQ专家博主👍掘金签约作者👍B站&掘金&CSDN&思否等全平台账号:王中阳Go

评论

发布
暂无评论
裁员还能有天花板?_Go_王中阳Go_InfoQ写作社区