1. Go

1.1. 数组和切片

切片(slice)是指针类型,数组(array)是值类型

  • 数组的长度是其类型的一部分(数组的容量永远等于其长度,都是不可变的)
  • 数组的长度是固定的,而切片不是(切片是动态的数组)
  • 切片比数组多一个属性:容量(cap)
  • 切片的底层是数组

1.2. make和new差别,引用类型的意义

new ()是内建函数,函数原型为:

func new(Type) *Type*

make 也是内建函数,它的函数原型 比 new 多了一个(长度)参数,返回值也不同:

//第一个参数是一个类型,第二个参数是长度

//返回值是一个指向该类型的一个引用

func make(Type, size IntegerType) Type

  • make和new都是golang用来分配内存的內建函数,且在堆上分配内存,并为该变量执行了初始化操作make 用于为引用类型分配内存空间,其在分配内存的同时,也初始化了一些相关属性(这里初始化这些相关属性时不再是简单的用默认零值来初始化了!!!)。new只是分配默认零值内存并返回指向该零值内存的一个指针也就是执行了一个默认初始化,全部用默认零值来进行初始化)
  • make返回的是一个引用类型;而new返回的是一个指向零值内存空间的指针。
  • make只能用来分配及初始化引用类型:slice,map,channel的数据;new可以分配任意类型的数据。

1.3. 逃逸分析

  • 逃逸分析是一种确定指针动态范围的方法,可以分析在程序的哪些地方可以访问到指针。它涉及到指针分析和形状分析
  • 如果一个子程序分配一个对象并返回一个该对象的指针,该对象可能在程序中的任何一个地方被访问到——这样指针就成功“逃逸”了
  • 逃逸分析需要确定指针所有可以存储的地方,保证指针的生命周期只在当前进程或线程中。

1.3.1. 逃逸分析的用处(为了性能)

最大的好处应该是减少gc的压力,不逃逸的对象分配在栈上,当函数返回时就回收了资源,不需要gc标记清除。

因为逃逸分析完后可以确定哪些变量可以分配在栈上,栈的分配比堆快,性能好。

同步消除,如果你定义的对象的方法上有同步锁,但在运行时,却只有一个线程在访问,此时逃逸分析后的机器码,会去掉同步锁运行。

  • go消除了堆和栈的区别

go在一定程度消除了堆和栈的区别,因为go在编译的时候进行逃逸分析,来决定一个对象放栈上还是放堆上,不逃逸的对象放栈上,可能逃逸的放堆上。

  • 开启逃逸分析日志

编译参数加入 -gcflags '-m -l'

  • 其中-m 打印逃逸分析信息,-l禁止内联优化

go build -gcflags '-m -l' main.go

理解逃逸分析一定能帮助我们写出更好的程序。知道变量分配在栈堆之上的差别,那么我们就要尽量写出分配在栈上的代码,堆上的变量变少了,可以减轻内存分配的开销,减小gc的压力,提高程序的运行速度。

所以,你会发现有些Go上线项目,它们在函数传参的时候,并没有传递结构体指针,而是直接传递的结构体。这个做法,虽然它需要值拷贝,但是这是在栈上完成的操作,开销远比变量逃逸后动态地在堆上分配内存少的多。当然该做法不是绝对的,如果结构体较大,传递指针将更合适。


1.3.2. channel的实现


1.3.3. gmp与gc,重点问题(网络io等待队列,读写屏障)


1.4. map的实现,重点问题(sync.map的实现,map实现随机的方法)


results matching ""

    No results matching ""