golang知识点

1、对于slice的截取

s := make([]int, 10000)
fmt.Println("s len:", len(s), " cap:", cap(s))
a := s[:3]
fmt.Println("a len:", len(a), " cap:", cap(a))
b := s[3:]
fmt.Println("b len:", len(b), " cap:", cap(b))

输出:

s len: 10000  cap: 10000
a len: 3  cap: 10000
b len: 9997  cap: 9997

2、channel的有无缓冲、关闭与否

// 无缓冲
c1 := make(chan int)
// 有缓冲
c2 := make(chan int, 1)

// 情况1
c1 = nil
// action ① 输出什么
c1 <- 1
// action ② 输出什么
rlt := <- c1

// 情况2
close(c1)
// action ① 输出什么
c1 <- 1
// action ② 输出什么
rlt = <- c1

// 情况3
c2 <- 1
close(c2)
// action ① 输出什么
c2 <- 2     
// action ② 输出什么
rlt = <- c2  

答案:

给⼀个 nil channel 发送数据,造成永远阻塞

从⼀个 nil channel 接收数据,造成永远阻塞

给⼀个已经关闭的 channel 发送数据,引起 panic

从⼀个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回⼀个零值,否则返回缓冲区中的值。并且可以无限读,只不过最后读到的都是0值。
另外在接收chan的值的时候,可以通过rlt, ok := <-c2的方式来获取,但是ok的true和false并不知道c2是否close,只能知道c2中是否还有数据未读取。
3、常量为什么不能寻址?
比如:
const a = 1

func main(){
    fmt.Println(&a)
}
4、字符串转成byte数组,会发生内存拷贝吗?
首先拷贝的方式有两种:
一种是大家熟知的是直接用[]byte("1")或string([]byte{'1'})强转,这种强制类型转换的方式是存在内存拷贝的,只是当数据小的时候,拷贝的数据少;当数据量大的时候,还会涉及内存空间的新建,性能消耗会更大。
另一种是通过反射出底层数据结构,将data的指针重新指向,这样的方式是没有内存拷贝的,但不安全,因为string是不可变的,如果转成[]byte后做了修改,那么会报错。
5、什么场景是recover不了的?
 s := "123"
 sh := *(*reflect.StringHeader)(unsafe.Pointer(&s))

 b := []byte{}
 bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
 bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
 defer func(){
        e := recover()
        fmt.Println(e)
 }()
 b[0] = '4'

b[0] = '4'这行会报错,并且recover不了。因为string是不可修改的,你变相修改。

6、字节长度和字符长度

import "fmt"
import  "unicode/utf8"

func main(){
        s := "今天"
        fmt.Println("length bytes",len(s))
        fmt.Println("length chars", utf8.RuneCountInString(s))
}

输出:

length bytes 6
length chars 2

7、unsafe包的用途

绕过Go语言的类型系统,直接操作内存,例如:我们一般不能操作结构体的未导出成员,但是通过unsafe包就能做到,unsafe包让我们可以直接读写内存,不需要管导出与未导出

8、slice的扩容策略

切片的扩容都是调用 growSlice 方法;

如果期望的大小比2倍的当前容量还大,那么直接用期望的大小;否则,如果期望的大小小于1024,则用2倍的当前容量,如果大于1024,则for循环,每次给当前容量增长1.25倍,直到满足需求。

9、内存逃逸

go内存管理器会给函数分配一个栈帧,用来存放栈上分配的变量,比如形参,局部变量,返回值。编译器会在函数执行完成后自动释放栈帧,但是有的变量由于一些需求,我们不希望被释放,这时候这种变量(一般是指针对象)就会逃逸到堆空间,这就是内存逃逸。

go提供了一个在编译期间的工具,用来分析代码中的逃逸情况:

 go builds -gcflags '-m -m -l'

常见的逃逸情况:

① 返回值是指针对象

② interface{}类型的变量,动态变量,需要在运行中才能确定

③ 超大的变量

④ 闭包函数,闭包会使用函数域内的变量,当闭包结束的时候,函数内部还在引用这个变量,并没有随着闭包而释放

10、GC的原理

go语言会在运行时有通过垃圾回收机制(GC)来对堆上的内存空间进行自动回收,减轻开发人员的负担,以确保内存空间的连续性和有效性。但是GC带来的开销随着空间的浪费和滥用而增加,GC需要定时遍历哪些堆上的对象是不可达的,将其清除掉。目前GC用的是标记清除法,对堆上对象通过三色标记和写屏障来清除不可达的对象。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值