
源码阅读
文章平均质量分 96
xjx
不入流的大龄码农一枚
展开
-
Go内存管理(下)
在每个P中都有一个pageCache类型的字段pcache,我们称为页的缓存。就是它保存了一组等待被使用的连续的页。对于要分配的的page数小于16个page的内存,我们都会先从pcache中查找是否有空闲的空间可供分配,pageCache结构体被用于实现P(处理器)的本地内存页缓存,这种结构体的设计有助于提高内存分配的效率和性能,特别是在多线程或并发环境下。结合pageCache的结构定义,base表示这一组连续页的起始地址,cache是一个uint64对象,在64位机器上是8个字节,即64个bit。原创 2024-01-31 17:13:43 · 1026 阅读 · 1 评论 -
Go内存管理(上)
在进入本章内容学习之前,最好能够对虚拟内存以及一些基本的物理内存知识有一定了解,这样能帮助更好的深入理解一些概念。为了缩减内容篇幅,聚焦重点内容,就不一一去讲解了,这边提供几个相关内容的参考地址,如下:虚拟内存知识可以参考该地址: https://blog.youkuaiyun.com/qqxjx/article/details/133852071物理内存知识可以参考该地址:https://blog.youkuaiyun.com/qqxjx/article/details/134119042。原创 2023-12-19 17:02:38 · 1081 阅读 · 0 评论 -
GO调度模型-GMP(下)
集齐各部分理论碎片之后,我们可以尝试对 的宏观调度流程进行整体串联,开始进入到调度函数, 此时的执行权位于 手中:分析代码,我们去掉一些非关键的逻辑和问题,总结起来该函数流程就两个:下面对这两个函数进行重点分析。调度流程中,一个非常核心的步骤,就是为 寻找到下一个执行的 ,这部分内容位于函数 方法中,该函数非常冗长,为了寻找一个可用的,真是用心良苦,我们看下源码分析:综合代码,来总结下流程:总结起来就是各种办法找,到最后还不死心,在能找的地方再找一次。其流程图如下:下面来根据 函数,来看看调度原创 2023-11-28 17:22:02 · 699 阅读 · 0 评论 -
GO调度模型-GMP(上)
首先我们要先了解g0和m0,首先要了解什么是g0和m0g0 g可以看出m0和g0都是全局变量,分别对应着m结构体和g结构体, 但是他们和普通的g和m还是有着区别的。m0启动程序后的编号为0的主线程,如果进程中不开任何线程,可以理解为一个进程就是一个线程;定义在全局变量runtime.m0中,不需要在heap(堆)上分配;负责执行初始化操作和启动第一个gg0启动第一个g之后,m0就和其他的m一样了( 负责给其他m进行抢占 )。每次启动一个m,都会第一个创建的goroutine,就是g0g0。原创 2023-11-15 10:39:53 · 719 阅读 · 0 评论 -
Linux - 物理内存
在虚拟内存文章中,我们知道进程的虚拟内存布局以及相关知识。为了能够承上启下,我们下面从计算机组成原理的角度介绍物理内存的相关概念,以便后续能够将虚拟内存与物理内存知识进行关联串联,使自己更深入的了解内存管理相关知识点,最后对的内存管理进行解析。内核是以页()为基本单位对物理内存进行管理的,内核将整个物理内存按照页对齐方式划分成千上万个页()进行管理,每页大小为 。系统中每个都是的一个实例,那么针对一个内存,那么将会存在上百万个结构。 中封装了每页内存块的状态信息,比如:组织结构,使用信息,统计信息,以及与其原创 2023-10-30 14:43:06 · 1712 阅读 · 0 评论 -
Go同步原语之sync/Pool
Pool本质是为了提高临时对象的复用率;Pool使用两层回收策略(localvictim)避免性能波动;Pool本质是一个杂货铺属性,啥都可以放。把什么东西放进去,预期从里面拿出什么类型的东西都需要业务使用方把控,Pool池本身不做限制;Pool池里面cache对象也是分层的,一层层的cache,取用方式从最热的数据到最冷的数据递进;Pool是并发安全的,但是内部是无锁结构,原理是对每个P都分配cache数组(数组),这样cache结构就不会导致并发;永远不要copy一个Pool。原创 2023-09-15 11:06:36 · 509 阅读 · 2 评论 -
Go同步原语之sync/Map
在结构体内容部分介绍过,entry.p是一个nilexpunged、其他正常值。那nilexpunged有啥区别呢?其实nilexpunged都用来表示keynilread map和dirty map在物理上仍保有该key-entry对,因此倘若此时需要对该entry执行写操作,可以直接CAS操作;expungeddirty map中已经没有该key-entry对,倘若执行写操作,必须加锁(dirty map必须含有全量key-entry对数据);设计expunged和nil。原创 2023-09-06 17:22:58 · 260 阅读 · 1 评论 -
Go同步原语之sync/Once
方法传入的函数中再次调用方法会有什么问题吗?})})通过分析sync.Once的源码,可以看到它包含一个名为m的互斥锁字段。当我们在Do方法内部重复调用Do方法时,将会多次尝试获取相同的锁。但是mutex互斥锁并不支持可重入操作,因此这将导致死锁现象。方法中传入的函数发生了panic,重复传入还会执行吗?err!= nil{})}()})在执行的过程中如果f出现panic,后面也不会再执行了;所以不会打印任何东西,方法中传入的函数只会被执行一次,哪怕函数中发生了panic;原创 2023-09-04 11:39:49 · 228 阅读 · 2 评论 -
Go同步原语之sync/waitGroup ---- 等待组
WaitGroup可以用于一个goroutine等待多个goroutine干活完成,也可以多个goroutine等待一个goroutine干活完成,是一个多对多的关系Add(n>0)方法应该在启动goroutine之前调用,然后在goroution内部调用Done方法WaitGroup必须在Wait方法返回之后才能再次使用Done只是Add的简单封装,所以实际上是可以通过一次加一个比较大的值减少调用,或者达到快速唤醒的目的。原创 2023-09-01 11:00:38 · 895 阅读 · 2 评论 -
Go同步原语之sync/mutex ---- 互斥锁
Mutex(互斥锁)是一种用于多线程编程的同步机制。它是""(互斥)的缩写,用于控制多个线程对共享资源的访问,以避免出现并发访问引起的问题,如数据竞争(Data Race)和不一致性。在多线程环境中,多个线程可以并发地访问共享资源,例如共享变量、数据结构或文件等。如果没有适当的同步机制,多个线程可能会同时修改同一份数据,导致不可预测的结果或者程序错误。使用互斥锁可以确保在任意时刻只有一个线程能够获得锁,从而访问共享资源。当一个线程获得了互斥锁,其他试图获得锁的线程会被阻塞,直到持有锁的线程释放锁。原创 2023-08-30 17:51:59 · 473 阅读 · 1 评论 -
Go语言基础知识点 —— Memory Alignment 内存对齐
为了更好的了解内存对齐概念,我们先要了解下内存的一些物理结构以及CPU和内存之间数据交互基础知识,一般内存的外形图片如下:一个内存是由若干个黑色的内存颗粒构成,每一个黑色的内存颗粒叫做一个chip,市面上大多数内存条都有8个chip,而每个chip拥有8张二维矩阵bankbank是由一个个的存储单元组成的矩阵,每个cell存储一个(8个小电容)数据 ,bank的每一行就叫做一个,每一列叫做一个,通过colum和row可以定位一个cell。cell示意图:了解完大概的内存结构后,我们来了解CPU。原创 2023-07-26 16:30:02 · 268 阅读 · 1 评论 -
Go语言基础知识点 —— Closure 闭包
闭包是函数值和引用环境的组合。闭包可以捕获包含它的函数作用域内的变量。闭包可以在函数结束后继续访问和修改捕获的变量。每次调用函数时都会创建一个新的闭包实例,每个闭包实例都有自己的引用环境和捕获的变量。闭包可以用于实现状态的保持和共享,尤其在并发编程中很有用。闭包的生命周期可能会比函数长,因为它可以在函数结束后仍然被其他部分引用和使用。使用闭包时要注意避免出现不必要的内存泄漏,确保在不需要时释放对捕获变量的引用。闭包在Go语言中被广泛使用,可以帮助我们编写更灵活和功能强大的代码。原创 2023-07-25 17:16:20 · 189 阅读 · 1 评论 -
Go语言基础结构 —— Channel 通道
在Go语言中,channel(通道)是一种用于在goroutine之间进行通信和同步的特殊数据结构。它可以看作是一条管道,可以在不同的goroutine之间传递数据。使用通道,你可以在goroutine之间发送和接收值。通道提供了一种安全、同步的方式来共享数据。它确保在发送操作完成之前,接收操作会一直等待,并且在接收操作完成之前,发送操作也会一直等待。这种同步机制可以有效地避免并发访问共享数据时出现的竞争条件和数据竞争。Golang并发的核心哲学是不要通过共享内存进行通信。原创 2023-06-25 11:56:27 · 2043 阅读 · 0 评论 -
Go语言基础结构 —— Interface 接口
接口是Go语言编程中数据类型的关键。在Go语言的实际编程中,几乎所有的数据结构都围绕接口展开,接口是Go语言中所有数据结构的核心。Go语言中的接口实际上是一组方法的集合,接口和gomock配合使用可以使得我们写出易于测试的代码.但是除了在反射等使用场景中我们很难直接感知到接口的存在(虽然大多数人使用反射的时候也没有感知到接口在其中发挥的作用),但是想要深入理解Go语言,我们必须对接口有足够的了解.接下来我们将从接口的数据结构、结构体如何转变成interface和Go语言中动态派发的实现这些方面来一起学习。原创 2023-06-15 17:33:08 · 2274 阅读 · 0 评论 -
Go语言基础结构 —— func 函数
在Go语言中,使用func关键字来定义函数。// 函数体 }其中:函数声明:关键字func代表是函数的名称,函数名由字母、数字、下划线组成。但函数名的第一个字母不能是数字。在同一个包内,函数名称不能重名。parameter1和parameter2代表是函数的参数,type是参数的类型。参数由参数变量和参数变量的类型组成,参数变量可以省略,可以有一个参数,也可以有多个,也可以没有;多个参数之间使用分隔;多个参数时参数变量要么全写,要么全省略;原创 2023-06-09 16:35:22 · 2494 阅读 · 0 评论 -
上下文-Context
Golanggoroutine,它是有Golang在Golang中,我们无法从外部终止一个协程,只能它自己结束。常见的比如超时取消等需求,我们通常使用抢占操作或者中断后续操作。在Context出来以前,Golang是的方式来做这件事情的。具体的做法是:定义一个channel,子协程启一个定时任务循环监听这个channel,主协程如果想取消子协程,就往channel里写入信号。这时我们需要一种优雅的方案来实现这样一种机制,Context就派上用场了。原创 2023-04-18 18:30:35 · 357 阅读 · 0 评论 -
Go语言基础结构 —— Map 哈希表
来看一个例子, 给定一个数组数据:, 求该组数据中是否有元素100O(N)BSTO(log N)那么有没有一种方法使查找效率更高呢?我们的一种思路是这样的:创建一个以数组最大值作为长度的的数组temp;以原数组中值作为数组temp的键值最后查找哪个元素是否存在就直接返回temp数组中该索引下标位置即可这边我们巧妙借助了数组的索引下标,直接返回某元素对应的索引下标值即可,于是我们想到构造一种存储结构,使,这样依据存储位置直接便查找到了该元素。这就是哈希表(hashmap)的最原始思路。原创 2023-05-24 09:21:42 · 524 阅读 · 0 评论 -
Go语言基础结构 —— Slice 切片
在Go语言中,切片(Slice)是一种数据结构,它是对数组一个连续片段的引用,这个数组称为切片的底层数组。切片和数组的关系是非常紧密的。在Go语言中,数组是一个固定长度的序列,而切片则是一个可变长度的序列。切片是建立在数组之上的,它提供了动态数组的功能,可以根据需要动态地增加或缩小切片的长度。原创 2023-05-15 10:22:53 · 1739 阅读 · 0 评论 -
Go语言基础结构 —— Array 数组
数组是go语言中的特殊类型,其与其他语言不太一样。他不可以添加,但是可以获取值,获取长度。数组的拷贝都是值拷贝,因此不要尽量不要进行大数组的拷贝。常量的下标以及某一些变量的下标的访问越界问题可以在编译时检测到,但是变量的下标的数组越界问题只会在运行时报错。数组的声明中,存在一个语法糖。,但是本质本没有什么差别在编译期的优化阶段,还会进行重要的优化。当数组的长度小于4时,在运行时会在栈中进行初始化。当数组的长度大于4,会在静态区初始化数组其实我们在go。原创 2023-05-08 09:58:08 · 989 阅读 · 0 评论