0%

在Go语言中,为了控制低级别的 runtime 行为,官方提供了一些环境变量,主要有:

  • GOGC
  • GODEBUG
  • GOMAXPROCS
  • GORACE
  • GOTRACEBACK

初次之外,还有用于编译期的 GOROOTGOPATHGOOSGOARCH,以及用于玩转SSA的 GOSSAFUNC

阅读全文 »

ELF(Executable and Linking Format) 是linux系统下可执行文件,目标文件,共享链接库和内核转储文件的格式。维基百科中是这样描述的:

在计算机科学中,ELF文件是一种用于可执行文件、目标文件、共享库和核心转储(core dump)的标准文件格式。其中核心转储是指: 操作系统在进程收到某些信号而终止时,将此时进程地址空间的内容以及有关进程状态的其他信息写出的一个磁盘文件。这种信息往往用于调试。

  • 可重定位文件(relocatable file) 它保存了一些可以和其他目标文件链接并生成可执行文件或者共享库的二进制代码和数据;
  • 可执行文件(excutable file) 它保存了适合直接加载到内存中执行的二进制程序;
  • 共享库文件(shared object file 一种特殊的可重定位目标文件,可以在加载或者运行时被动态的加载进内存并链接。
  • 核心转储文件(core dump) 是操作系统在进程收到某些信号而终止运行时,将此时进程地址空间的内容以及有关进程状态的其他信息写入一个磁盘文件。这种信息往往用于调试。

ELF文件主要由四部分组成:

  • ELF Header:主要包括文件的类型,架构,程序入口地址,Program HeaderSection 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 的前缀组合,它对外只暴露了两个方法:LockUnlock,本篇文章将详细了解加解锁背后的逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// A Mutex is a mutual exclusion lock.
// The zero value for a Mutex is an unlocked mutex.
//
// A Mutex must not be copied after first use.
type Mutex struct {
state int32
sema uint32
}

// A Locker represents an object that can be locked and unlocked.
type Locker interface {
Lock()
Unlock()
}

// 一些状态
const (
mutexLocked = 1 << iota // 1:表示锁定状态
mutexWoken // 2: 表示当前锁被从正常模式唤醒
mutexStarving // 4: 表示当前锁进入互斥状态
mutexWaiterShift = iota // 3:左移3位存储正在等待获取锁的goroutine的个数
starvationThresholdNs = 1e6 // 正在获取锁的goroutine等待1ms之后,会让当前锁进入饥饿模式
)
阅读全文 »

本文借助 visual studio code 搭建本地的 dapr 应用开发环境,另外讲述本地调试技巧,便于问题定位。

还是来调试 dapr 为我们准备的示例应用,secretstore,我们先将本地的 dapr 按照官方指导运行起来,并且将示例应用克隆到本地打开,另外还需安装好 Dapr Visual Studio Code扩展 ,并且执行 npm install 命令安装将应用的扩展,当所有就绪之后你的工作区应该看起来如下所示:

阅读全文 »

Dapr 在 2021 年发布了 v1.0 生产可用版本,预示着这个号称分布式运行时的框架终于可以进入各种大企业。说是尝鲜那已经是晚了很多,讲内部实现目前还不了解,本文主要是记录自己在本地创建 k8s 集群并且跑起来我第一个基于dapr应用的辛酸过程,辛酸是因为对k8s及dapr都不熟悉,加之国内网络限制,M1 芯片对某些软件不支持导致。

阅读全文 »

sync.Pool 是一组临时对象,可以用来被复用,以减少内存分配次数,降低GC压力,在大量相同临时对象存在的场景下使用,能较好处理因GC导致CPU突增的情况。sync.Pool 使用比较简单,只有三个简单的 API:NewGetPut,并且它是并发安全的,意味着它可以在 goroutine 中安全地使用。

阅读全文 »

每个语言都有自己的依赖管理系统,就像 CargonpmComposerNugetPipMaven 等,Go 语言也不能例外,在 go mod 出来之前,有两种模式:

  • GOPATH 模式,这种模式把问题想象的太过于简单理想化,可以说是Go语言设计的败笔,因为不支持对依赖的版本管理,不同的项目依赖同一个第三方库的不同版本,GOPATH 就无法搞定,只能切来切去。

  • vendor 模式,这种模式将第三方依赖下载到项目的 vendor 目录下,实现了不同项目之间相互隔离,但是也不支持对依赖的版本管理,没有统一的地方进行声明,一更新就会升级到最新版本,不像很多语言中,将项目的依赖固化到一个 *_lock.json 版本中,这样在项目转移到其他地方进行编译,能确保得到一致的功能。当然,也有很多人喜欢将 vendor 目录上传到仓库,保持不同地方编译后二进制一致性,不过这样会导致仓库体积过大,有利有弊。

在这种背景下,诞生了很多第三方的依赖管理工具,如:govendorglidedep等,为了解决这种乱象,Go官方出品了 Go Modules,一统江山,其他第三方管理工具就都成为了历时。

阅读全文 »

Rust 中的每一个引用都有其生命周期(lifetime),也就是引用保持有效的作用域。大部分时候生命周期是隐含并可以推断的,正如大部分时候类型也是可以推断的一样。但有些时候,Rust 需要我们使用泛型生命周期参数来注明他们的关系,这样就能确保运行时实际使用的引用绝对是有效的。

阅读全文 »