欢迎访问我的博客,你的支持,是我最大的动力!

Go语言学习笔记(9)-安全/测试/内存管理

Linux 小马奔腾 324℃ 评论
目录:
[显示]

安全

对称加密:DES AES RC4等
非对称加密:RSA
不可解密:哈希算法:MD5 SHA-1

通信安全

哈希函数
md5 sha-1等

md5、sha1的使用

对文件进行md5和sha1

HTTPS原理:
SSL/TLS 在服务器返回证书并检查完证书合法性后,使用证书中公钥加密一个随机对称密钥,服务器用私钥解密这个随机对称密钥后,服务器与浏览器之间使用对称加密进行通信

支持HTTPS的Web服务器

支持HTTPS的文件服务器

测试

单元测试(Unit Testing)又称模块测试

单元测试

通过 go test 命令能自动执行如下形式的函数:
func TestXxxx(*testing.T)  //Xxxx第一个字母必须大写
编写测试模块,要创建名称以 _test.go 结尾的文件,该文件包含TestXxx函数,并将该文件放在与被测试包相同的包目录中,该文件将被排除在正常程序包之外,只在运行 go test 时被调用
go help test 和 go help testflag 可以查看帮助

单元测试示例

运行 go test

表组测试

测试覆盖率

测试中使用 t.Errorf 时,若某个情况测试失败,不会中止测试

测试方法及后续动作:
1、Fail,记录失败信息,继续执行
2、FailNow,记录失败信息,中断测试
3、SkipNow,不记录失败用例信息,中止测试
4、Skip,记录失败信息,中断测试
5、Skipf,记录失败信息,中断测试,格式化输出
6、Log,输出错误信息,继续执行
7、Logf,输出格式化信息,继续执行
8、Error,相当于 Log+Fail,继续执行
9、Errorf,相当于 Log+Fail,继续执行,格式化输出
10、Fatal,相当于 Log+FailNow,中断测试
11、Fatalf,相当于 Log+FailNow,中断测试,格式化输出

默认,单元测试成功时,打印信息不会输出,可使用 -v 选项
基准测试,总是会输出

模拟测试

模拟网络访问,可使用标准库的 httptest 包,可模拟 HTTP 的网络调用

利用 httptest.NewRecorder() 创建http.ResponseWriter ,模拟真实服务器端的响应,响应通过调用 http.DefaultServeMux.ServeHTTP 方法触发

模拟一个服务器,进行调用测试

这个模拟的服务器,监听的是127.0.0.1,端口是随机的;发送get请求,不再发送/sendjson,而是模拟服务器地址的server.URL

覆盖率测试

测试覆盖率,由单元测试的代码触发运行的被测试代码行数占所有代码行数的比例

# 显示测试覆盖率
go test -v -coverprofile=c.out
## -coverprofile 指定生成覆盖率文件
# 生成报告 依据c.out文件生成html的报告文件
go tool cover -html=c.out -o=tag.html

基准测试

基准测试,benchmarking,测量和评估软件性能指标,建立一个已知的性能水平(基准线)
基准测试的函数必须以  Benchmark 开头,如
func BenchmarkXxx(*testing.B)
执行:go test -bench

go test -bench=. -run=none
# -bench=. 表示运行所有基准测试 -run=none 匹配一个不存在的单元测试 过滤掉单元测试的输出(默认会运行单元测试)
# BenchmarkHello-4 10000000 103 ns/op
表示执行了 10000000次,每次循环用时103ns -4表示运行时对应的GOMAXPROCS的值
基准测试默认执行1秒钟,可以指定运行时长 -benchtime=3s 建议测试时间不超过3秒
go test -bench=. -run=none -benchtime=3s

若运行前需要一些耗时的配置,可以在代码中重置定时器,b.ResetTimer()

若基准测试需要在并行设置中测试性能,可使用RunParallel 辅助函数 这样的测试一般与 go test -cpu 标志一起使用

执行:go test -bench=. -run=none -benchtime=1s -cpu=4

1、性能对比
对比哪种性能更加高效

运行:go test -bench=. -run=none
# -benchmem 可提供每次操作分配内存的次数 及每次操作分配的字节(B)数
go test -bench=. -run=none -benchmem
## BenchmarkSprintf-4 10000000 148 ns/op 16 B/op 2 allocs/op
其中 allocs/op 表示每次操作从堆上分配内存的次数;B/op 表示每次操作分配的B数

注意,要将所有要进行基准测试的代码都放到循环里,且循环要使用b.N的值,否则测试的结果不可靠

2、pprof
分析函数具体执行状况

常用选项:
-bench regexp,regexp是正则表达式 表示需要运行的基准测试函数 一般用 -bench . 匹配所有
-benchmem,包含内存分配统计信息
-benchtime t,运行时间
-cpuprofile out,输出cpu profile到指定路径 可使用pprof查看
-memprofile out,输出内存profile到指定路径 可以使用pprof查看

pprof是go提供的性能分析工具,可分析cpu profile、memory profile、heap profile、block profile等信息

go test -bench=. -run=none -benchmem -cpuprofile=cpu.prof
# 生成cpu.prof
go tool pprof cpu.prof
# 查看cpu.prof文件 会进入交互环境
# 交互环境中可使用的命令:top10
top10
# 1750ms 29.97% 29.97% 2240ms 38.36% strconv.FormatInt
第一列 1750ms 每次采样10ms 即175次
第二列 29.97% 落在该函数里取样点占总取样点的百分比
第三列 29.97% 前几行加起来的执行时间点总执行时间的比例
第四列 2240ms 取样点落在该函数里和它直接调用、间接调用的函数里的总数
第五列 38.36% 第四列的时间占总时间的比例
list BenchmarkFormat  显示某函数各行占用时间
top BenchmarkFormat 显示某函数的执行时间情况

内存管理

Go语言是内置运行时的编程语言,自主管理内存
内存管理基于TCMalloc(Google开发的内存分配器),优点:对抗内存碎片、在多核心处理器上可伸缩

内存地址:
计算机上的每个进程都认为自己可以访问所有物理内存
内核把物理页作为内存管理的基本单位 page
操作系统维持一个虚拟地址到物理地址的转换表
mmap()

内存中的栈和堆:
栈和堆指内存中的一个区域
堆可视为一组大小不同的块 chunk
堆的内存分配效率相比栈比较低  效率:栈 > 堆

栈区一般由操作系统自动分配释放,是连续的内存区域,数据结构是栈
堆区一般由程序员分配释放、或由OS回收数据结构类似链表
静态分配是系统编译器完成的,如局部变量的分配,局部变量一般是分配到栈区
堆区用于分配开发人员申请的内存空间,静态变量、全局变量一般分配到堆区
只读区分配常量和程序代码空间

逃逸分析:
栈的性能要比堆好很多,分配内存的速度比堆快(小内存分配)
逃逸分析是确定指针动态范围的方法

go run -gcflags="-m -l" main.go
# -m 开启逃逸分析 -l 不让编译器自动内连函数
# command-line-arguments
.\main.go:5:9: &x escapes to heap
.\main.go:4:6: moved to heap: x
.\main.go:8:10: toStack new(int) does not escape

Go在一定程度上消除了堆栈的区别,编译时会自动进行逃逸分析,不逃逸的对象放在栈上,可能逃逸的对象放在堆上

手动控制内存分配到堆栈的规则:
1、Go中的变量只要被引用就一直存活,存储在堆还是栈由内部实现决定,和具体语法没关系
2、一般情况会将函数局部变量分配到函数栈 stack frame
3、若变量在函数 return 后还会被引用 编译器会将变量分配到堆上
4、若一个局部变量非常大,会被分配到堆上
5、若一个变量被取址(*和&) 很可能会被分配到堆上 最终结果还是要做逃逸分配 若函数 return 后变量不再被引用 会分配到栈上

go run -gcflags="-m -l" main.go

TCMalloc

TCMalloc 对多线程做了优化,小对象的分配基本不存在锁竞争;大对象使用了细粒度、高效的自旋锁 spinlock 特别适用于高并发场景

ThreadCache -> CentralCache -> PageHeap -> OS
线程私有性,每个线程都有一份,理想状况下,线程在自己的ThreadCache里完成,不需要竞争,非常高效
PageHeap是中内堆分配器,所有线程共享,分配时需要全局锁定;大尺寸的内存直接使用PageHeap分配
内存分配粒度,object和span,object是span切成的小块,有88种规格,同一个span切出来的object是相同规格的,object不超过256KB
ThreadCache和CentralCache是管理object的;PageHeap是管理span的
离散式空闲列表算法

小内存分配
大内存分配
TCMalloc中定义的page大小为8KB,系统page大小为4KB
PageHeap是按page申请内存,但是管理内存的基本单位是span

Mspan 内存管理器
内存分为两部分,一部分是堆,供内存分配;另一部分是bitmap,用来管理堆

Go中,内存分配器只管理内存块,不关心对象状态,不主动回收内存,需由垃圾回收器完成清理操作后,再触发内存管理器回收内存

垃圾回收
基于标记清理算法
并发标记和清理;写屏障;非分代;非紧缩
标记清理算法分为两阶段:
标记阶段,从root区域出发,扫描所有root区域的对象直接或间接引用到的对象,将这些对象全部加上标记
回收阶段,扫描整个堆区,对所有无标记的对象进行回收

自动垃圾回收和主动垃圾回收
主动垃圾回收,调用 runtime.GC(),这是阻塞式的
gcpercent值通过环境变量 GOGC 获取,默认是100 ,若设置成off,则关闭垃圾回收

两种GC触发方式,自动检测和用户主动调用,除此之外,Go语言本身会对运行状态进行监控,超过两分钟没有GC,会触发GC,监控函数是 sysmon()

转载请注明:轻风博客 » Go语言学习笔记(9)-安全/测试/内存管理

喜欢 (0)or分享 (0)