2021-10-30
Linux进程内存分布简介
#
在Linux系统中,一个程序进程在内存布局上遵循一定规律,进程的内存空间布局由高地址到低地址大致可分为以下几段:
- 栈(stack): 用户态的栈,栈的大小是固定的,其大小可以使用
ulimit -s
查看和调整,一般默认为8Mb,栈从高地址向低地址增长(函数调用) - 堆(heap): 动态分配的内存空间,程序在运行时动态分配和释放,堆内存的分配不是连续的,整体上是从低地址向高地址增长
- bss(未初始化数据区): 未初始化数据区bss, 存放全局的未初始化赋值的变量
- data(初始化数据区): 存放已经初始化的全局变量数据
- text: 存放程序代码
...2021-10-28
Delve是一个专门用于Go语言的调试器,之前整理过Delve的基本使用,使用Delve调试Go程序。
本文进一步介绍如何使用Delve阅读Go的源码并找到一些语法在Go的内部是如何实现的。这里将一下在Go里创建channel的语法为例make(chan int, 100)
,演示如何使用Delve如何找到make chan在Go内部的源码实现以及channel具体的数据结构是什么样的。
...2021-10-20
Delve是一个使用Go语言开发的专门用于Go语言的调试工具。Delve项目的地址是https://github.com/go-delve/delve,
这个项目的目标是为Go提供一个简单的、功能齐全、易于调用和使用的调试器。当前Go语言支持GDB、LLDB、Delve三种调试工具,LLDB是MacOS系统推荐的,已经成为了XCode默认调试器,但GDB和LLDB对Go的支持比不上Delve这个专门为Go设计和开发的调试工具。
Goland
和Go for Visual Studio Code
这种集成开发环境的调试功能也都是集成了delve的。
本文将学习Delve命令行的基本使用。
...2020-08-16
Go 1.15继1.14 6个月后发布,主要是在工具链、运行时和类库上的改进,改版本继续保持对Go 1.x版本的兼容性。
Go 1.15值得关注的变化
#
Go 1.15中一些值得关注的地方:
- 对Go链接器的实质性改进
- 改进了对高核心计数的小对象的分配
- X.509 CommonName弃用
- GOPROXY支持跳过返回错误的代理
- 新增了一个
time/tzdata
包 - 核心库的一些改进
从这些变化上可以看出,这个版本变化不太大,其实在工具链和运行时上也不需要过多关注,直观的体验是编译的二进制文件大小确实比1.14小了一点点。
...2020-08-10
1.为什么要内存对齐?
#
先来看一下字长的概念。字长是CPU的主要技术指标之一,指的是CPU一次能并行处理的二进制位数,通常CPU的字长为4字节(32位)、8字节(64位)。
CPU在访问内存时,并不是逐个字节访问的,而是以字长为单位访问。这么做的目的是为了减少CPU访问内存的次数,例如对于64位CPU,一次读取16字节数据只需要读取2次。
...2019-03-12
Go Modules是Go 1.11引入的,为了解决Go项目的依赖问题。从go 1.16开始,go modules开始成为Go默认的包依赖管理工具。
go moudle是一组go package的集合
#
一个Go Module实际上是由一组Go的Package的集合。
构建Go Module的过程需要先确定依赖的其他Go Module的版本、编译包、将编译的目标文件链接到一起。
...2019-02-12
三种多线程模型
#
操作系统的线程由内核的线程调度器负责调度,不同的编程语言对内核线程的封装不同,有以下三个模型:
N:1
模型: N个用户空间线程运行在1个内核空间线程上。优点是上下文切换快,缺点是无法有效利用多核特性。
在该模型下,线程管理由用户空间的线程库进行,因此上下文切换效率高,但如果某个用户线程执行阻塞系统调用(syscall),其他用户线程也将会阻塞。因为任一时间只能有一个内核空间线程访问内核,所以多个用户线程也就无法并行运行在多核系统上。
由于无法有效利用系统多核特性,所以现在几乎没有编程语言使用这个模型。1:1
模型: 1个用户空间线程运行在1个内核空间线程上。每次调度都要在用户态和内核态之间切换,因此该模型的缺点是上下文切换很慢,而且每创建一个用户线程就需要创建一个内核线程,因此可以创建的用户线程数量也会受限制。
在该模型下,一个用户线程执行阻塞系统调用时,能够允许其他用户线程继续执行,多个用户线程也可以并行的运行在多核系统上。使用此模型的编程语言有Java。M:N
模型: 多个用户空间线程运行在多个内核空间线程上。M:N
模型综合了N:1
和1:1
模型的优点,多路复用多个用户空间线程到一定数量的内核空间线程。这种模型的缺点是调度实现起来十分复杂。Go采用的这种模型,用户空间线程在Go中对应的是Goroutine。
Goroutine调度器和G-M-P
模型
#
在Go中用户线程的调度和生命周期管理都是用户层面的,由Go语言自己实现,不依赖OS系统调用,减少系统资源消耗。
Go实现了一个自己的运行时调度器用于调度Goroutine(轻量级的用户空间线程)。
...2019-02-10
模拟枚举类型
#
go语言中虽然没有Java, C++等一些高级语言提供的枚举类型特性,但可以使用常量和iota来模拟。
例如:
1// BuildResult 构建结果
2type BuildResult int
3
4const (
5 // Success 成功
6 Success BuildResult = iota
7 // Fail 失败
8 Fail
9 // Abort 中断
10 Abort
11)
1var buildResult = Success
2println(buildResult) // 0
使用go generate和stringer生成String() string函数
#
为了打印枚举类型值具体的字符串标识,可以使用https://godoc.org/golang.org/x/tools/cmd/stringer
工具并结合go generate
为枚举类型生成func (t T) String() string
函数。这样枚举类型就实现了fmt.Stringer
接口。具体的实现方式是在枚举类型BuildResult的定义上加上注释//go:generate stringer -type=BuildResult
:
...2018-11-06
Go语言interface的运行时实现的源码位于$GOROOT/src/runtime/runtime2.go
中。
在Go的不同版本中,interface的实现可能会有不同,但整体结构变化不大,本文基于Go 1.17。
1.两类接口的运行时实现
#
可以在runtime/runtime2.go
中找到Go的接口类型变量在运行时的表示,如下是iface
和eface
两个结构体:
...2017-02-18
基础
#
IDE
#