面向对象理解interface
golang修养之路
理解interface
- interface 是方法声明的集合
- 任何类型的对象实现了在interface 接口中声明的全部方法,则表明该类型实现了该接口
- interface 可以作为一种数据类型,实现了该接口的任何对象都可以给对应的接口类型变量赋值
开闭原则
对扩展开放,对修改封闭
依赖倒转原则
程序要依赖于抽象接口,不要依赖于具体实现
内存逃逸和内存泄露
go程序员面试笔试宝典
腾讯云 素履coder
内存逃逸
Go语言编译器通过分析代码来决定将变量分配到何处
- 如果函数外部没有引用,则优先放到栈中,栈空间不足时放到堆上;
- 如果函数外部存在引用,则必定放到堆中;(内存逃逸)
- 不可预知大小的内存分配堆到堆
以下命令在构建程序的时候输出内存逃逸信息
1
|
go build -gcflags '-m -l' main.go
|
内存泄露
slice内存泄漏
slice只使用底层数组的一部分
time.Ticker
没有stop会导致定时任务一直在发送
goruntine
主要是CSP模型下,goruntine死锁的情况
设计模式
博客园 aganippe
go语言设计模式
创建型模式
简单工厂模式
NewXXX 函数返回接口时就是简单工厂模式
函数返回实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//API is interface
type API interface {
Say(name string) string
}
//NewAPI return Api instance by type
func NewAPI(t int) API {
if t == 1 {
return &hiAPI{}
} else if t == 2 {
return &helloAPI{}
}
return nil
}
|
工厂方法模式
工厂方法模式使用子类的方式延迟生成对象到子类中实现。Go中不存在继承 所以使用匿名组合来实现
工厂结构体的create方法返回实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
//Operator 是被封装的实际类接口
type Operator interface {
SetA(int)
SetB(int)
Result() int
}
//OperatorBase 是Operator 接口实现的基类,封装公用方法
type OperatorBase struct {
a, b int
}
//SetA 设置 A
func (o *OperatorBase) SetA(a int) {
o.a = a
}
//SetB 设置 B
func (o *OperatorBase) SetB(b int) {
o.b = b
}
//OperatorFactory 是工厂接口
type OperatorFactory interface {
Create() Operator
}
//PlusOperatorFactory 是 PlusOperator 的工厂类
type PlusOperatorFactory struct{}
func (PlusOperatorFactory) Create() Operator {
return &PlusOperator{
OperatorBase: &OperatorBase{},
}
}
//PlusOperator Operator 的实际加法实现
type PlusOperator struct {
*OperatorBase
}
//Result 获取结果
func (o PlusOperator) Result() int {
return o.a + o.b
}
|
抽象工厂模式
抽象工厂模式用于生成产品族的工厂,所生成的对象是有关联的
单例模式
使用懒惰模式的单例模式,使用双重检查加锁保证线程安全
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//Singleton 是单例模式类
type Singleton struct{}
var singleton *Singleton
var once sync.Once
//GetInstance 用于获取单例模式对象
func GetInstance() *Singleton {
once.Do(func() {
singleton = &Singleton{}
})
return singleton
}
|
模板模式
廖雪峰
定义一个操作的一系列步骤,对于某些暂时确定不下来的步骤,就留给子类去实现好了,这样不同的子类就可以定义出不同的步骤
Geth区块链
博客园 王陸
搭建自己的以太坊私链
GoGC
CSDN smartaconf
golang修养之路
Go V1.3之前的标记-清除(mark and sweep)算法
暂停程序业务逻辑, 找出不可达的对象,然后做上标记,最后回收标记好的对象
需要程序暂停!即 STW(stop the world)
1.3将回收的过程放到STW的后面以提高部分效率
Go V1.5的三色并发标记法
白灰黑
- 所有对象都是白色
- 遍历程序根对象,将其变为灰色
- 重复将灰色对象变成黑色对象,然后把引用的对象变成灰色对象
- 没有灰色对象时删除白色对象
屏障机制
围绕白被黑引用
强三色不变式:白色对象不能被黑色对象引用
弱三色不变式:白色对象可以被黑色对象引用但必须被灰色对象引用或间接引用
插入屏障:强三色不变式。堆空间对象A引用B对象时B对象被标记为灰色。栈空间回收白色对象之前STW,然后三色标记扫描。
删除屏障:弱三色不变式。被取消引用白色对象标记为灰色。这种方式的回收精度低,一个对象即使被删除了最后一个指向它的指针也依旧可以活过这一轮,在下一轮GC中被清理掉。
Go V1.8的混合写屏障(hybrid write barrier)机制
弱三色不变式。屏障技术是不在栈上应用的,因为要保证栈的运行效率
- GC开始将栈上的对象全部扫描并标记为黑色(之后不再进行第二次重复扫描,无需STW)
- GC期间,任何在栈上创建的新对象,均为黑色
- 被堆对象取消引用的堆对象标记为灰色
- 被堆对象引用的堆对象标记为灰色(包括已存在的对象)
设置GC频率
使用环境变量GOGC的值n,它表示已使用内存增长到前一次GC内存时占用率的n%时触发GC
当然在代码中也可以通过os包修改环境变量来实现设置GC频率
1
|
os.Setenv("GOGC", "50")
|
如何优雅的让主函数阻塞
- 使用通道(Channel):
1
2
3
4
|
func main() {
ch := make(chan struct{})
<-ch
}
|
- 使用sync.WaitGroup:
1
2
3
4
5
6
7
8
9
|
func main() {
var wg sync.WaitGroup
wg.Add(1)
go func() {
// Do something...
wg.Done()
}()
wg.Wait()
}
|
- 使用select{}语句:
1
2
3
|
func main() {
select {}
}
|
开销最小是3
推荐2
Govulncheck
Go 语言的安全守护者 polarisxu
扫描代码中使用的模块和包,并与 GoVulnDB 进行比对,找出可能存在的风险,并给出修复建议
安装
1
|
go install golang.org/x/vulndb/cmd/govulncheck@latest
|
使用:扫描当前目录的所有代码