当前位置:   article > 正文

golang面试题总结(附带答案,持续更新中)

golang面试题

channel知识点

1.传入channel的值是原来的备份,从channel中取出来的值也是通道中值的备份

2.如果想通过channel传输同一个值,那么可以传递这个值的指针

3.如果关闭channel要从发送端关闭,如果从接收端关闭会引发恐慌

4.发送端关闭通道不会影响接收端接收

5.带缓冲区和不带缓冲区的channel区别就是长度是否为0,不带缓冲区的channel的长度就是0

6.操作未被初始化的通道会造成永久阻塞

go的map底层原理

底层结构

指向桶数组的指针

指向旧桶数组的指针

B 2^B个桶的数量

溢出桶的数量

储存溢出桶的extra

查找()

赋值(先查找后赋值)

先通过低B位找到是哪个编号的桶,在桶里面通过高八位进行循环判断,如果高八位相同了,在进行全部hash值的判断

删除

gmp模型

go的gc(标记清理->三色标记法->混合写屏障)

标记清理:

在一开始使用的便是标记清除法

标记清除法的缺点:

1.需要stw

2.标记需要扫描整个heap

3.清除数据会产生heap碎片

三色标记法:

1.就是只要是新创建的对象,默认的颜色都是标记为“白色”.

2.每次gc开始从根节点开始遍历所有对象,把遍历过的节点从白色集合加入到灰色集合

3.遍历灰色集合,把灰色对象引用的白色对象 从白色集合放入灰色集合,之后将此灰色对象放入黑色集合

4.重复3,直到灰色中无任何对象

5.回收所有的白色标记表的对象,也就是回收垃圾

然而三色标记法也需要stw

否则以下两种情况同时发生的时候会导致 对象丢失现象

条件1.一个白色对象被黑色对象引用

条件2.灰色对象与他之间的可达关系的白色对象遭到了破坏(灰色同时丢失了该白色)

而且如果白色对象 还有很多对象的话,也会一并清理掉

而使用stw有着明显的资源浪费

于是屏障机制就踹出来了

强-弱 三色不变性
强三色不变性

不存在黑色对象引用白色对象的指针

img

弱三色不变性

所有被黑色对象引用的白色对象都处于灰色保护状态

img

插入屏障和删除屏障用来实现上面的两种不变性

屏障
插入屏障
具体操作:

在A对象引用B对象的时候,B对象被标记为灰色(将B挂在A下游,B必须被标记为灰色)

满足 :强三色不变性

不存在黑色对象引用白色对象的情况了,因为白色会强制变成灰色

伪代码
添加下游对象(当前下游对象slot, 新下游对象ptr) {   
  //1
  标记灰色(新下游对象ptr)   
  
  //2
  当前下游对象slot = 新下游对象ptr                   
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

黑色对象的内存槽有两种位置,栈和堆,栈空间的特点是容量小,但是要求响应速度快,又因为函数调用弹出频繁使用,所以插入屏障机制在栈空间中不使用,而仅仅使用在堆空间对象的操作中(为了响应速度考虑)

缺点

只能删除清除对空间中的对象

删除屏障
具体操作:

被删除的对象,如果自身为灰色或者白色,那么被标记为灰色

满足:弱三色不变式

保护灰色对象到白色对象的路径不会断

伪代码
添加下游对象(当前下游对象slot, 新下游对象ptr) {
  //1
  if (当前下游对象slot是灰色 || 当前下游对象slot是白色) {
        标记灰色(当前下游对象slot)     //slot为被删除对象, 标记为灰色
  }
  
  //2
  当前下游对象slot = 新下游对象ptr
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
缺点

回收精度低,一个对象及时被删除了,最后一个指向他的指针也依旧可以活过这一轮,在下一轮gc中被回收掉

可见两者都有缺点,于是混合写屏障

混合写屏障v1.8

插入写屏障:因为只能用堆空间上,结束时需要STW来重新扫描栈,标记栈上引用 的白色对象的存活

删除写屏障:回收精度低,gc开始时stw扫描堆栈来记录初始快照,这个过程会保护开始时刻所有存活的对象

go1.8的混合写屏障,避免了对栈的re-scan的过程,极大的减少了STW的时间,结合了两者的优点

具体操作

1.gc开始将栈上的对象全部扫描并标记为黑色(之后不再进行第二次重复扫描,无需stw)

2.gc期间,任何在栈上创建的新对象,junweiheise

3.被删除的对象标记为黑色

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

满足:变形的弱三色不变式
伪代码
添加下游对象(当前下游对象slot, 新下游对象ptr) {
    //1 
        标记灰色(当前下游对象slot)    //只要当前下游对象被移走,就标记灰色
    
    //2 
    标记灰色(新下游对象ptr)
        
    //3
    当前下游对象slot = 新下游对象ptr
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

屏障技术是不在栈上应用的,因为要保障栈的运行效率

总结

go v1.3

整体过程需要启动stw,效率极低

go v1.5

堆空间启动写屏障,栈空间不启动,全部扫描后,需要重新扫描一遍栈(需要stw),效率普通

go v1.8

三色标记法,混合写屏障机制,栈空间不启动,堆空间启动。整个过程几乎需要stw,效率极高

更详细的看

https://www.jianshu.com/p/4c5a303af470

协程goroutine

go中用for遍历多次执行,goroutine会存在什么问题?怎么改进?

错误的使用goroutine

func goroutineRun(values []int)  {
    for value := range values {
        go func() {
            fmt.Println(value)
        }()
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
错误原因:

实际是遍历数组的所欲变量,由于闭包只是绑定到这个value变量上,并没有保存到goroutine栈中,所以以上代码极有可能运行的结构都输出为切片的最后一个元素。因为这样写会导致for循环结束后才执行goroutine多线程操作,这时候value值只指向了最后一个元素。这样的结果不是我们所希望的,而且还会产生并发的资源抢占冲突,所以是非常不推荐这样写的

解决方法

for val := range values {
    go func(val interface{}) {
        fmt.Println(val)
    }(val)
}
  • 1
  • 2
  • 3
  • 4
  • 5
解决原因

这里val作为一个参数传入goroutine中,每个val都会被独立计算并保存到goroutine的栈中,从而得到预期的结果,另一种方法是循环内定义新的变量,由于在循环内定义的变量在循环遍历的过程中是不共享的,因此也可以达到相同的效果

for i := range valslice {
    val := valslice[i]
    go func() {
        fmt.Println(val)
    }()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果在每个goroutine中都获取返回值(捕获参数),有哪些方案(全局参数,channel,闭包)

gmp当一个g堵塞时,g,m,p会发生什么

怎么做的链接复用,怎么支持的并发请求的,go的netpoll是怎么实现的?像阻塞read一样去使用底层的非阻塞read

go协程的实现方式

channel的实现方式

map的底层实现

怎么确定走go语言技术栈的

go map 底层 扩容机制

有缓存和无缓存channel的区别

new 和 make的区别

2个协程交替打印字母和数字

gmp模型

协程和线程的区别

golang内存模型

golang并发模型

golang gc原理 过程

channel用途 原理

简述go语言gmp调度呕心

简单问了下go语言的引用类型有什么

g会不会饥饿,为什么?p的数量是多少?能修改吗?m的数量是多少

p和m的数量一定是1:1吗?如果一个G阻塞了会怎么样

讲一下gc的原理,三色标记法?还懂其他的gc原理吗?

逃逸分析说下?为什么要逃逸分析?如何避免逃逸

并发控制的方法?chan sync包

chan的相关问题,如关闭一个已经关闭的chan会如何,有缓存和无缓存的区别是什么?

关闭一个已经关闭的channle 会 pannic : close of closed channel

关闭channel的知识点(只能关闭双向channel或者发送channle,关闭后向关闭的channel发送数据回发生pannic,而向关闭的channel读取数据将会读完最后一个后返回0值)

问了context的作用,哪些场景使用过context

父goroutine退出,如何使得子goroutine也退出

channel的实现原理?答了环形队列,问为什么使用环形队列

map的key可以是那种类型?可以嵌套mapma

map中对于key的哈希是怎么计算的?

defer怎么用的

channel使用场景

讲了gmp调度

go slice和map的区别,slice和数组的区别

go结构体和结构体指针的区别

go深拷贝,什么时候需要用到深拷贝

如何拿到多个goroutine的返回值,如何区别他们

go如何避免panic

结构体创建优化

gochannel实现顺序

度过什么go源码没有

go语言gc了解吗

go什么场景使用接口

结构体传递场景

go的profile工具

go语言什么时候垃圾回收,写代码的时候如何减少对象分配

实现map的方法除了hash还有哪些

go的gc了解吗

gmp具体的调度策略二

go实现不重启热部署

go性能分析工具

goroutine创建数量有限制吗

go并发机制

go内存操作也要处理io,是如何处理的

gomap并发安全问题,如何解决

gogc

一个进程能创建的进程数量受到哪些制约

go切片和数组map,gc,gmp调度模型

gmp调度模型

syncpool的实现原理

while(true)(sleep(1))这个会有什么问题

sleep底层实现原理

同一个协程里面,对无缓存channel同时发送和接收数据有什么问题

channel和锁对比一下

channel的应用场景

slice和arrayqubie

向nil的channel发送数据会怎么样

map取一个key,然后修改这个值,原map数据的值会不会变化

k8s原理

gostruct能不能比较

select可以用于什么

context包的用途

主协程如何等待其余协程完在操作

slice len cap 共享 扩容

map如何顺序读取

goroutine在项目里面是什么作用

数组和切片的关系和区别

内存申请上有什么区别

函数传递有什么区别

切片底层的架构

如何数组转换成一个切片

gmp模型说一下

服务能开多少个m由什么决定

开多少个p由什么界定

m和p是什么样的关系

同时开启了1万个g,如何调度的?

go里面的channel是什么样的概念

channel和共享内存有什么优劣势

111

ubie

向nil的channel发送数据会怎么样

map取一个key,然后修改这个值,原map数据的值会不会变化

k8s原理

gostruct能不能比较

select可以用于什么

context包的用途

主协程如何等待其余协程完在操作

slice len cap 共享 扩容

map如何顺序读取

goroutine在项目里面是什么作用

数组和切片的关系和区别

内存申请上有什么区别

函数传递有什么区别

切片底层的架构

如何数组转换成一个切片

gmp模型说一下

服务能开多少个m由什么决定

开多少个p由什么界定

m和p是什么样的关系

同时开启了1万个g,如何调度的?

go里面的channel是什么样的概念

channel和共享内存有什么优劣势

111

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/89118
推荐阅读
相关标签
  

闽ICP备14008679号