Hero Image
「Go」内存分配

重点剖析Go运行时的内部机制,深入了解Go运行期状态,规避GC潜在的问题,节约内存,提升运行性能 环境 Mac环境 (不建议使用,会有很多困扰,直接用Linux) Debian环境 编译好的可执行文件真正的执行入口并不在main.go的mian()函数中。编译器总会插入一段引导代码,完成命令行参数、运行时初始化等工作才会进入用户逻辑。 编译&GDB调试 main.go 1package main 2 3func main() { 4 println("hello world") 5} -gcflags “-N -l” 关闭编译器代码优化和函数内联,避免断点和单步执行无法准确对应源码行,避免小函数和局部变量被优化掉 1go build -gcflags "-N -l" 2# go build -gcflags "-N -l" -o test main.go 通过info files可以找到程序真正的入口地址0x105a8c0 ,利用断点命令可以找到目标源文件信息。 Mac 下breakpoint 并未显示对应的文件信息,以下所有的操作均在Debian中查看。 不同的操作系统就使用不同的汇编文件 下面这这个汇编文件完成了初始化和运行时的启动动作。 调用初始化函数 创建main goroutine用于执行runtime.main 让当前线程开始执行main goroutine 至此,汇编语言针对特定平台的引导过程全部完成,后续的内容基本上都是由Go代码实现的。 go的汇编 Go ASM 和标准的汇编语法( NASM 或 YASM )不太一样,首先你会发现它是架构独立的,没有所谓的 32 或 64 位寄存器,如下图所示: Tips:Mac 配置gdb环境 GDB Installation on Mac OS X

Hero Image
Go 设置Golang开发环境

安装Go 开始写Golang之前,你首先需要下载并且安装Golang开发工具。可以在Golang的官方网站下载最新的安装包。根据你的开发平台选择下载对应的版本。对于Mac用户(或者Windows用户)来说.pkg(或msi)安装包会自动把Golang安装到合适的位置,并将命令加入到环境变量,并且自动移除老版本。如果使用Mac更加推荐直接使用brew install go, 使用brew 可以方便的管理Go多个版本。 对于Linux或者FreeBSD用户可以直接下载对应的.tar.gz, 并解压到文件名为go的目录中。把这个文件Copy到/usr/local/下。然后把/usr/local/go/bin添加到$PATH中。 1tar -C /usr/local -xzvf go1.17.3.linux-amd64.tar.gz 2# change .profile to .bashrc or.zsh depend on you evnironment 3echo "export PATH=$PATH:/usr/local/go/bin" >>$HOME/.profile Go 程序编译完成后是一个独立的二进制文件,不需要依赖任何运行软件(例如,Python需要Python解释器,Java需要JVM)。仅在需要编译Go代码的环境上安装Go即可。 安装完成后,打开Terminal(Window 打开CMD),验证Go是否安装成功。 1go version 在所有的配置都正确的情况下,可以看到输出的版本信息 1# mac intel cpu 64bit 2go version go1.17.3 darwin/amd64 从上述信息中可以看出,Go的版本是1.17.3,使用的开发机器是 Mac(Darwin 是MacOS的Kernel Name, amd64 是指64-bit的x86 CPU架构)。 如果你没有得到正确的版本信息,很有可能是你没有把go加入到环境变量,或者有其他的程序名称也为go。对于Mac或者Unix-like用户,可以使用which go查看当前环境下的go的是否正确关联到/usr/local/go/bin。如果路径正确,也有可能是下载错了安装包,检查下安装包的位数是否与当前操作系统匹配,有可能在64-bit的系统上下载了32-bit的安装包。另外,也有可能是芯片架构选错了。 Go 工作空间 从2009年Go开始使用,在开发者如果组织代码和管理依赖上经历了几次变化。在Go 1.11所有的代码必须保存在GOPATH之下,之后的版本用户可以在任意目录下存储自己的代码。但是Go依然希望有一个独立的工作空间可以存储通过go install安装额第三方包。默认的工作空间是$HOME/go, 下载的第三方包默认存储在$HOME/go/src,编译的二进制文件存储在$HOME/go/bin。你可以直接使用这个默认的工作空间,或者通过设置$GOPAHT指定一个工作空间。 无论你是否使用默认的wokespace,建议你把$GOPATH/bin加入到$PATH中。 通过指定$GOPATH可以清楚地描述当前环境的Go工作空间,把$GOPATH/bin加入到可执行路径中可以直接使用go install 安装的第三方包。 如果是Unix-like的开发环境可以把下面几行加入到$HOME/.profile中。 1# if use ubuntu you should add to .

Hero Image
基本语法梳理

源文件 原文件使用UTF-8编码,对Unicode支持良好。每个源文件都属于包的一部分,在文件头部用package声明所属包的名称 1package main 2func main(){ 3 println("hello world!!") 4} 以.go作为文件扩展名,语句结束分号会被默认省略,支持C样式注释。入口函数main没有参数,且必须放在main包中 用import导入标准库或第三方包 1package main 2import{ 3 "fmt" 4} 5 6func main(){ 7 fmt.Println("hello world!") 8} 可以直接运行或者编译为可执行文件 变量 使用var定义变量,支持类型推断。基础数据类型划分清晰明确,有助于编写跨平台应用。编译器确保变量总是被初始化为0,避免出现意外状况。 1package main 2func main(){ 3 var x int32 4 var s="hello world!" 5 // 两个数据之间默认使用空格隔开 6 println(x,s) 7} 在函数内部,还可以省略var关键字,使用更简单的定义模式。 1package main 2 3//y := 200 // 该声明方式仅在函数内部使用,不可用来声明全局变量 4func main() { 5 x := 100 6 println(x) 7} 编译器将未使用的局部变量定义当做错误 表达式 Go仅有三种流控制语句 if 1package main 2 3func main() { 4 x := 100 5 if x > 0 { 6 print("x") 7 } else if x < 0 { 8 print("-x") 9 } else { 10 print("0") 11 } 12} switch 1package main 2 3func main() { 4 x := 0 5 switch { 6 case x > 0: 7 print("x") 8 case x < 0: 9 print("-x") 10 default: 11 print("0") 12 } 13} for 1func main() { 2 for i := 0; i < 5; i++ { 3 println(i) 4 } 5 for i := 4; i >= 0; i-- { 6 println(i) 7 } 8} 1package main 2 3func main() { 4 x := 0 5 for x < 5 { // 相当于 while(x<5) 6 println(x) 7 x++ 8 } 9} 1package main 2 3func main() { 4 x := 4 5 for { // 相当于while(true) 6 println(x) 7 x-- 8 if x < 0 { 9 break 10 } 11 } 12} 在迭代遍历时,for…range除了元素外,还可以返回索引