【Golang】汇编语言
汇编语言是最接近机器代码的人类可读语言,通过阅读汇编代码,我们可以了解到自己所编写的高级语言代码最终生成的指令都是什么,以便更好的掌握高级语言和了解计算机系统。Go 语言的汇编器基于 Plan9 汇编器,并且在此基础之上定义了一些创新。
在Go语言中,为了控制低级别的 runtime
行为,官方提供了一些环境变量,主要有:
GOGC
GODEBUG
GOMAXPROCS
GORACE
GOTRACEBACK
初次之外,还有用于编译期的 GOROOT
,GOPATH
,GOOS
和 GOARCH
,以及用于玩转SSA的 GOSSAFUNC
。
ELF(Executable and Linking Format)
是linux系统下可执行文件,目标文件,共享链接库和内核转储文件的格式。维基百科中是这样描述的:
在计算机科学中,ELF文件是一种用于可执行文件、目标文件、共享库和核心转储(core dump)的标准文件格式。其中核心转储是指: 操作系统在进程收到某些信号而终止时,将此时进程地址空间的内容以及有关进程状态的其他信息写出的一个磁盘文件。这种信息往往用于调试。
可重定位文件(relocatable file)
它保存了一些可以和其他目标文件链接并生成可执行文件或者共享库的二进制代码和数据;可执行文件(excutable file)
它保存了适合直接加载到内存中执行的二进制程序;共享库文件(shared object file
一种特殊的可重定位目标文件,可以在加载或者运行时被动态的加载进内存并链接。核心转储文件(core dump)
是操作系统在进程收到某些信号而终止运行时,将此时进程地址空间的内容以及有关进程状态的其他信息写入一个磁盘文件。这种信息往往用于调试。ELF
文件主要由四部分组成:
ELF Header
:主要包括文件的类型,架构,程序入口地址,Program Header
和 Section Header
的大小,数量,偏移量等;
Programe Header
:列举所有有效的 segments
的属性,描述如何创建进程运行时内存镜像,当内核看到这些 segments
时,使用 mmap
将他们映射到虚拟地址空间,为程序的运行准备;
Section
:在ELF
文件中,数据和代码分开存放的,这样可以按照其功能属性分成一些区域,比如程序、数据、符号表等。这些分离存放的区域在ELF文件中反映成section
;
Section Header
:定义ELF文件中所有的 section
,用于链接和重定位。对于可执行文件,有四个主要部分:.text
、.data
、.rodata
和 .bss
;
ELF 文件各个部分的布局如下:
UML
是一种开放的方法,用于说明、可视化、构建和编写一个正在开发的、面向对象的、软件密集系统的制品的开放方法。UML展现了一系列最佳工程实践,这些最佳实践在对大规模,复杂系统进行建模方面,特别是在软件架构层次已经被验证有效。
本篇文章记录 Go
进程的启动和初始化过程,从程序入口开始调试,探索 Go
的各个组件初始化,以最简单的 hello world
为示例。
在Go语言中,实现并发编程相当简单,因此存在大量场景需要同步操作限制对临界区的修改,避免出现不可期望的情况。因此,Go 语言在 sync
中提供了大量的基本同步原语,例如,最常见的互斥锁 sync.Mutex
,它的名字应该来源于:Mutual Exclusion
的前缀组合,它对外只暴露了两个方法:Lock
和 Unlock
,本篇文章将详细了解加解锁背后的逻辑。
1 | // A Mutex is a mutual exclusion lock. |
本文借助 visual studio code 搭建本地的 dapr 应用开发环境,另外讲述本地调试技巧,便于问题定位。
还是来调试 dapr 为我们准备的示例应用,secretstore,我们先将本地的 dapr 按照官方指导运行起来,并且将示例应用克隆到本地打开,另外还需安装好 Dapr Visual Studio Code扩展 ,并且执行 npm install
命令安装将应用的扩展,当所有就绪之后你的工作区应该看起来如下所示:
sync.Pool
是一组临时对象,可以用来被复用,以减少内存分配次数,降低GC压力,在大量相同临时对象存在的场景下使用,能较好处理因GC导致CPU突增的情况。sync.Pool
使用比较简单,只有三个简单的 API:New
,Get
和 Put
,并且它是并发安全的,意味着它可以在 goroutine 中安全地使用。
每个语言都有自己的依赖管理系统,就像 Cargo
,npm
,Composer
, Nuget
, Pip
, Maven
等,Go 语言也不能例外,在 go mod
出来之前,有两种模式:
GOPATH
模式,这种模式把问题想象的太过于简单理想化,可以说是Go语言设计的败笔,因为不支持对依赖的版本管理,不同的项目依赖同一个第三方库的不同版本,GOPATH
就无法搞定,只能切来切去。
vendor
模式,这种模式将第三方依赖下载到项目的 vendor
目录下,实现了不同项目之间相互隔离,但是也不支持对依赖的版本管理,没有统一的地方进行声明,一更新就会升级到最新版本,不像很多语言中,将项目的依赖固化到一个 *_lock.json
版本中,这样在项目转移到其他地方进行编译,能确保得到一致的功能。当然,也有很多人喜欢将 vendor
目录上传到仓库,保持不同地方编译后二进制一致性,不过这样会导致仓库体积过大,有利有弊。
在这种背景下,诞生了很多第三方的依赖管理工具,如:govendor
,glide
,dep
等,为了解决这种乱象,Go官方出品了 Go Modules
,一统江山,其他第三方管理工具就都成为了历时。