其他分享
首页 > 其他分享> > go 学习笔记

go 学习笔记

作者:互联网

go内存分配逃逸分析

https://www.iphpt.com/detail/137

逃逸分析(Escape Analysis):指由编译器解决内存分配的位置,不需要程序员指定。

在函数中申请一个新的对象:

注意:对于函数外部没有引用的对象,也有可能放到堆中,比如内存过大超过栈的存储能力。

go build -gcflags=-m

逃逸分析的作用是什么?

逃逸总结

函数传递指针真的比传值效率高吗?

我们知道传递指针可以减少底层值的拷贝,可以提高效率,但是如果拷贝的数据量小,由于指针传递会产生逃逸,可能会使用堆,也可能增加gc的负担,所以传递指针不一定是高效的。

TDD、BDD、ATDD、DDD 软件开发模式

https://blog.csdn.net/ejinxian/article/details/70212208

Go垃圾回收机制

http://interview.wzcu.com/Golang/Go垃圾回收机制.html

1 定义

垃圾回收gc:是在后台运行一个守护线程,它的作用是在监控各个对象的状态,识别并且丢弃不再使用的对象来释放和重用资源。

简单来说,垃圾回收的核心就是标记出那些内存还在使用中(即被引用到),那些内存不再使用了(即未被引用),把未被引用的内存回收掉,以供后续内存分配时使用。

2 垃圾回收触发时机

内存分配量到阀值触发GC

每次内存分配时都会检查当前内存分配量是否已到达阀值,如果达到阀值则立即启动gc。

阀值=上次GC内存分配量*内存增长率

内存增长率由环境变量GOGC控制,默认为100,即每当内存扩大一倍时启动GC。

定时触发GC

默认情况下,最长2分钟触发一次GC,src/runtime/proc.go:forcegcperiod变量中被声明:

// forcegcperiod is the maximum time in nanoseconds between garbage
// collections. If we go this long without a garbage collection, one
// is forced to run.
//
// This is a variable for testing purposes. It normally doesn't change.
var forcegcperiod int64 = 2 * 60 * 1e9

手动触发

程序代码中也可使用runtime.GC() 来手动触发GC,这主要用于GC性能测试和统计。

3 垃圾回收算法

引用计数:对每个对象维护一个引用计数,当引用该对象的对象被销毁是,引用计数减1,当引用计数器为0时回收该对象。

标记-清除:从根变量开始遍历所有引用的对象,引用的对象标记为“被引用”,没有被标记的进行回收。

分代收集:按照对象生命周期长短划分不同的代空间,生命周期长的放入老年代,而短的放入新生代,不同代又不通的回收算法和回收频率。

golang中的垃圾回收主要应用三色标记法,gc过程和其他用户goroutine可并发运行,但需要一定时间的STW(stop the world),STW的过程中,CPU不执行用户代码,全部用于垃圾回收,这个过程的影响很大,golang进行了多次迭代优化来解决这个问题。

单元测试

package main

import "fmt"

func firmwarePackAccept(serveIp, fileName string, tcpPort uint64) string {
	// 建立TCP监听
	ipandPort := fmt.Sprintf("%s:%d", serveIp, tcpPort)
	return ipandPort
}

package main

import "testing"

func Test_firmwarePackAccept(t *testing.T) {

	type args struct {
		serveIp  string
		fileName string
		tcpPort  uint64
	}
	a:=args{
		serveIp: "192.1.1.122",
		fileName: "a.zip",
		tcpPort: 66,
	}
	tests := []struct {
		name string
		args args
		want string
	}{
		// TODO: Add test cases.
		{"a",a,"192.1.1.122:66"},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := firmwarePackAccept(tt.args.serveIp, tt.args.fileName, tt.args.tcpPort); got != tt.want {
				t.Errorf("firmwarePackAccept() = %v, want %v", got, tt.want)
			}
		})
	}
}

写好方法以后,vscode右键Go: Generate Unit Tests For Function

image-20210915102613603

{"test", fields{start: true}, args{id: 0}},

Mutex锁、RWMutex锁和Once锁

golang中的sync包实现了两种锁:

Mutex(互斥锁)

1、Mutex 为互斥锁,Lock() 加锁,Unlock() 解锁

2、在一个 goroutine 获得 Mutex 后,其他 goroutine 只能等到这个 goroutine 释放该 Mutex

3、使用 Lock() 加锁后,不能再继续对其加锁,直到 Unlock() 解锁后才能再加锁

4、在 Lock() 之前使用 Unlock() 会导致 panic 异常

5、已经锁定的 Mutex 并不与特定的 goroutine 相关联,这样可以利用一个 goroutine 对其加锁,再利用其他 goroutine 对其解锁

6、在同一个 goroutine 中的 Mutex 解锁之前再次进行加锁,会导致死锁
适用于读写不确定,并且只有一个读或者写的场景

RWMutex(多读单写锁)

1、RWMutex 是单写多读锁,该锁可以加多个读锁或者一个写锁

2、读锁占用的情况下会阻止写,不会阻止读,多个 goroutine 可以同时获取读锁

3、写锁会阻止其他 goroutine(无论读和写)进来,整个锁由该 goroutine 独占
适用于读多写少的场景

Once锁

sync.Once是golang package中使方法只执行一次的对象实现,作用与init函数类型,但又不同:

sync.Once使用变量done来记录函数的执行状态,使用sync.Mutex和sync.atomic来保证线程安全的读取done.

初始化变量、结构体。

https://geektutu.com/post/hpg-sync-once.html

sync.Map

map需要用make函数对其进行分配内存和初始化,sync.Map不需要初始化,用锁机制来保证并发安全。

    //开箱即用
    var sm sync.Map
    //store 方法,添加元素
    sm.Store(1,"a")
    //Load 方法,获得value
    if v,ok:=sm.Load(1);ok{
        fmt.Println(v)
    }

https://blog.csdn.net/u010230794/article/details/82143179?ops_request_misc=&request_id=&biz_id=102&utm_term=go

指针

标签:笔记,goroutine,回收,学习,逃逸,内存,go,指针,引用
来源: https://www.cnblogs.com/gdf456/p/15833978.html