Avatar
😀

Organizations

  • 如何启用GC跟踪

    GODEBUG=gctrace=1 go run *.go

    其中 gctrace=1 表示只针对这个进程进行GC追踪

    标记流程

    go采用三色标记法,主要是为了提高并发度,这样扫描过程可以拆分为多个阶段,而不用一次扫描全部

    • 黑 根节点扫描完毕,子节点也扫描完毕

    • 灰 根节点扫描完毕,子节点未扫描

    • 白 未扫描

    扫描是从 .bss .data goroutine栈开始扫描,最终遍历整个堆上的对象树

    标记 mark

    标记过程是一个广度优先的遍历过程,扫描节点,将节点的子节点推送到任务队列中,然后递归扫描子叶节点,直到所有工作队列被排空

    mark阶段会将白色对象标记,并推入队列中变为灰色

    memory barrier

    保障了代码描述中对内存的操作顺序,即不会在编译期被编译器进行调整,也不会在运行时被CPU的乱序执行所打乱

    write barrier

    在应用进入 GC 标记阶段前的 stw 阶段,会将全局变量 runtime.writeBarrier.enabled 修改为 true,这时所有的堆上指针修改操作在修改之前便会额外调用 runtime.gcWriteBarrier

    由于GC和Go主程序并发执行,所以必须要在扫描时监控内存可能出现的状态改变,所以需要写屏障,所以需要暂停GO主程序(STW)

    hybrid wirte barrier (after go1.8)

    改方式的基本思想是:对正在被覆盖的对象进行着色,且如果当时栈未扫描完成,则同样对指针进行着色

    GC流程

    程序启动会为每个P分配一个 mark worker 来标记内存,负责为进入STW做前期工作

    • 起初认为所有 object 都被认定为白色
    • 但栈,堆和全局变量的object被标记为灰色

    GC会将灰色object标记为黑色,将灰色object所包含的所有指针所指向的地址都标记为灰色,递归这两个步骤,最终对象非黑即白,其中白色object即未被引用且可以被回收,如果object标记为no scan,则递归结束,标记为黑色

    todo https://blog.csdn.net/asd1126163471/article/details/124113816

    GC Created Sat, 26 Feb 2022 00:00:00 +0000
  • Golang 默认指针是类型安全的,但它有很多限制。Golang 还有非类型安全的指针,这就是 unsafe 包提供的 unsafe.Pointer。在某些情况下,它会使代码更高效,当然,也更危险。unsafe 包用于 Go 编译器,在编译阶段使用。从名字就可以看出来,它是不安全的,官方并不建议使用。Go 语言类型系统是为了安全和效率设计的,有时,安全会导致效率低下。unsafe 包绕过了 Go 的类型系统,达到直接操作内存的目的,使用它有一定的风险性。但是在某些场景下,使用 unsafe 包提供的函数会提升代码的效率,Go 源码中也是大量使用 unsafe 包。

    unsafe

    //定义
    type ArbitraryType int
    
    type Pointer *ArbitraryType 
    
    //函数
    func Sizeof(x AribitraryType) uintptr{}
    
    func Offsetof(x AribitraryType) uintptr{}
    
    func Alignof(x AribitraryType) uintptr{}
    

    分析

    • Pointer : 指向任意类型,类似于 C 中的 void*

    • Sizeof : 返回所传类型的大小,指针只返回指针的本身(x64 8byte x86 4byte),而不会返回所指向的内存大小。

    • Offsetof : 返回 struct 成员在内存中的位置,相对于此结构体的头位置,所传参数必须是结构体成员。传入指针,或者结构体本身,会 error

    • Alignof : 返回 M,M 是内存对齐时的倍数。

    • 任意指针都可以和 unsafe.Pointer 相互转换。

    • uintptr 可以和 unsafe.Pointer 相互转换。

    综上,unsafe.Pointer 是不能进行指针运算的,只能先转为 uintptr 计算完再转回 unsafe.Pointer ,还有一点要注意的是, uintptr 并没有指针的语义,意思就是 uintptr 所指向的对象会被 gc。而 unsafe.Pointer 有指针语义,可以保护它所指向的对象在“有用”的时候不会被垃圾回收。

    Created Wed, 25 Aug 2021 00:00:00 +0000
  • 简介

    Protocol Buffers,是Google公司开发的一种数据描述语言,类似于XML能够将结构化数据序列化,可用于数据存储、通信协议等方面。本文只介绍 syntax = proto3 的协议语法。

    标准类型对照

    .proto 注释 C++ Python Go C#
    double 定长编码 double float float64 double
    float 定长编码 float float float32 float
    int32 变长编码,负数编码效率低,可使用sint32 int32 int int32 int
    int64 变长编码,负数编码效率低,可使用sint64 int64 int/long int64 long
    uint32 变长编码 uint32 int/long uint32 uint
    uint64 变长编码 uint64 int/long unit64 ulong
    sint32 变长编码,对负数编码比int32更有效率 int32 int int32 int
    sint64 变长编码,对负数编码比int64更有效率 int64 int/long int64 long
    fixed32 总是4字节,如果值大于2^28uint32更有效率 uint32 int/long uint64 ulong
    fixed64 总是8字节,如果值大于2^56uint64更有效率 uint64 int/long uint64 ulong
    bool 1或0的变长编码 bool boolean bool bool
    string 必须是UTF-8编码 string str/unicode string string
    bytes 可包含任意的字节顺序 string str []byte ByteString
    Created Mon, 13 May 2019 00:00:00 +0000
  • 一个 os 线程会有一个给固定大小的内存块(一般是 2MB),用来存储当前线程中调用或挂起函数的内部变量,固定大小的栈对于复杂和深层次递归是不够的,而 Goroutine 会以一个很小的栈(2KB)开始其生命周期,这个栈会动态伸缩,最大能到达 1GB(32位系统是 250M)

    调度方式

    os 线程由操作系统内核调用,每过一定时间(毫秒),硬件计时器会中断处理器,并调用一个名为 scheduler 的内建函数,这个函数会挂起当前执行的线程并保存内存中它的寄存器内存,然后检查线程列表并决定下一次执行哪个线程,并从内存中恢复该线程的寄存器信息,恢复该线程的线程并执行,这就是上下文切换,增加了 CPU 的运行周期。而 Go 的 runtime 包含了自身的调度器,和 os 线程不同是,Goroutine 属于用户级线程由语言支持,调度由语言支持,所有开销会减少很多(相比于内核上下文切换)。

    goroutine Created Sun, 12 May 2019 00:00:00 +0000
  • Link

    Markdown语法

    目录

    只能跳转标题,如果有同名标题与标题等级无关,匹配最优先的标题

    Markdown Created Tue, 05 Mar 2019 00:00:00 +0000
Previous