meowrain

MeowRain

Life is Simple

Go垃圾回收机制

Go GC机制 5、Golang三色标记混合写屏障GC模式全分析 (yuque.com) 垃圾回收(Garbage Collection,简称GC)是编程语言中提供的自动的内存管理机制,自动释放不需要的内存对象,让出存储器资源。GC过程中无需程序员手动执行。GC机制在现代很多编程语言都支持,GC能力的性能与优劣也是不同语言之间对比度指标之一。 发展过程 Go V1.3之前的标记-清除(mark and sweep)算法,Go V1.3之前的标记-清扫(mark and sweep)的缺点 Go V1.3之前的标记-清除(mark and sweep)算法 接下来我们来看一下在Golang1.3之前的时候主要用的普通的标记-清除算法,此算法主要有两个主要的步骤: 标记(Mark phase) 清除(Sweep phase) STW会对可达对象做上标记,然后对不可达对象进行GC回收 操作非常简单,但是有一点需要额外注意:mark and sweep算法在执行的时候,需要程序暂停!即 STW(stop the world),STW的过程中,CPU不执行用户代码,全部用于垃圾回收,这个过程的影响很大,所以STW也是一些回收机制最大的难题和希望优化的点。所以在执行第三步的这段时间,程序会暂定停止任何工作,卡在那等待回收执行完毕。 mark and sweep 算法 缺点 STW会让程序暂停,使程序出现卡顿(重要问题) 标记需要扫描整个heap 清除数据会产生heap碎片 stw暂停范围 从上图来看,全部的GC时间都是包裹在STW范围之内的,这样貌似程序暂停的时间过长,影响程序的运行性能。所以Go V1.3 做了简单的优化,将STW的步骤提前, 减少STW暂停的时间范围.如下所示 上图主要是将STW的步骤提前了一步,因为在Sweep清除的时候,可以不需要STW停止,因为这些对象已经是不可达对象了,不会出现回收写冲突等问题。 但是无论怎么优化,Go V1.3都面临这个一个重要问题,就是mark-and-sweep 算法会暂停整个程序 。 Go是如何面对并这个问题的呢?接下来G V1.5版本 就用三色并发标记法来优化这个问题. GoV1.5三色标记法 三色标记法无STW的问题 我们加入如果没有STW,那么也就不会再存在性能上的问题,那么接下来我们假设如果三色标记法不加入STW会发生什么事情? 我们还是基于上述的三色并发标记法来说, 他是一定要依赖STW的. 因为如果不暂停程序, 程序的逻辑改变对象引用关系, 这种动作如果在标记阶段做了修改,会影响标记结果的正确性,我们来看看一个场景,如果三色标记法, 标记过程不使用STW将会发生什么事情? 我们把初始状态设置为已经经历了第一轮扫描,目前黑色的有对象1和对象4, 灰色的有对象2和对象7,其他的为白色对象,且对象2是通过指针p指向对象3的,如图所示。 现在如何三色标记过程不启动STW,那么在GC扫描过程中,任意的对象均可能发生读写操作,如图所示,在还没有扫描到对象2的时候,已经标记为黑色的对象4,此时创建指针q,并且指向白色的对象3。 与此同时灰色的对象2将指针p移除,那么白色的对象3实则就是被挂在了已经扫描完成的黑色的对象4下,如图所示。 然后我们正常指向三色标记的算法逻辑,将所有灰色的对象标记为黑色,那么对象2和对象7就被标记成了黑色,如图所示。 那么就执行了三色标记的最后一步,将所有白色对象当做垃圾进行回收,如图所示。 但是最后我们才发现,本来是对象4合法引用的对象3,却被GC给“误杀”回收掉了。 GC误杀条件 可以看出,有两种情况,在三色标记法中,是不希望被发生的。 条件1: 一个白色对象被黑色对象引用**(白色被挂在黑色下)** 条件2: 灰色对象与它之间的可达关系的白色对象遭到破坏**(灰色同时丢了该白色)** 如果当以上两个条件同时满足时,就会出现对象丢失现象!

Linux禁用ipv6

查看是否启用ipv6 首先,可以执行以下命令来检查 IPv6 是否已经启用: 1 ip a 临时禁用ipv6 1 2 3 sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1 sudo sysctl -w net.ipv6.conf.default.disable_ipv6=1 sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=1 检查是否生效 1 ip a 永久禁用ipv6 1 sudo vim /etc/sysctl.conf 在末尾添加 1 2 3 net.ipv6.conf.all.disable_ipv6=1 net.ipv6.conf.default.disable_ipv6=1 net.ipv6.conf.lo.disable_ipv6=1 应用 1 sudo sysctl -p 查看是否生效 1 ip a

Websocket服务端 Golang

服务端1 收到客户端消息马上发回给客户端 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package main import ( "log" "net/http" "github.com/gorilla/websocket" ) var upgrader websocket.Upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, } func socketHandler(w http.

Golang实现文件断点续传

Golang实现文件断点续传 HTTP 范围请求 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Range_requests https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Range https://juejin.cn/post/7381455296658751551?searchId=202406222022394BE0D5BA1F1DB137CFF5 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/206 我们首先用golang写一个不具备范围请求的代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 package main import ( "mime" "net/http" "os" "path/filepath" "strconv" "github.

Go Net/Http库

Go net/http库 Get()方法 函数原型 1 func Get(url string) (resp *Response, err error) 使用示例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package main import ( "fmt" "io" "log" "net/http" ) func main() { response, err := http.Get("http://httpbin.org/get") if err != nil { log.Fatal(err) } fmt.

Linux系统编程 标准IO 打开并读写文件

https://cplusplus.com/reference/cstdio/fopen/ https://cplusplus.com/reference/cstdio/fgetc/?kw=fgetc https://cplusplus.com/reference/cstdio/fputc/?kw=fputc https://cplusplus.com/reference/cstdio/fgets/?kw=fgets https://cplusplus.com/reference/cstdio/fputs/?kw=fputs https://man7.org/linux/man-pages/man3/getline.3.html https://cplusplus.com/reference/cstdio/feof/?kw=feof https://cplusplus.com/reference/cstdio/fclose/?kw=fclose https://cplusplus.com/reference/cstdio/fread/?kw=fread https://cplusplus.com/reference/cstdio/fwrite/?kw=fwrite https://cplusplus.com/reference/cstdio/fseek/?kw=fseek https://cplusplus.com/reference/cstdio/rewind/kw=rewind https://cplusplus.com/reference/cstdio/ftell/?kw=ftell fopen: 函数原型:FILE *fopen(const char *filename, const char *mode); 功能:打开一个文件,并返回一个指向该文件的文件指针(FILE 类型)。这个文件指针用于后续的文件读写操作。 参数: filename:指向一个以空字符结尾的字符串,该字符串指定要打开的文件名,可以包含路径信息。 mode:指向一个以空字符结尾的字符串,指定文件的打开模式。常见的模式包括: "r":以只读方式打开文件(文件必须存在)。 "w":以写入方式打开文件,如果文件不存在则创建,如果文件已存在则清空文件内容。 "a":以追加方式打开文件,如果文件不存在则创建,写入的数据追加到文件末尾。 "r+":以读写方式打开文件(文件必须存在)。 "w+":以读写方式打开文件,如果文件不存在则创建,如果文件已存在则清空文件内容。 "a+":以读取和追加方式打开文件,如果文件不存在则创建,读取从文件开始,写入追加到文件末尾。 还可以在上述模式后添加 "b" 来以二进制模式打开文件,例如 "rb"、"wb" 等。 返回值:成功时返回一个有效的文件指针,如果文件无法打开,则返回 NULL。 在使用 fopen 打开文件后,通常需要检查返回的文件指针是否为 NULL 来确保文件成功打开。文件使用完毕后,应使用 fclose 函数关闭文件,释放资源。例如: 1 2 3 4 5 6 7 8 9 10 11 12 13 FILE *fp; char *filename = "example.txt"; char *mode = "r"; fp = fopen(filename, mode); if (fp == NULL) { printf("无法打开文件\n"); return 1; } // 文件操作代码.

Linux系统编程-文件IO-缓冲区实例

行缓冲 在使用行缓冲的情况下,每当输入输出遇到换行或者缓冲区满了的情况下才会进行实际的IO操作,当涉及到终端输入输出的时候通常使用行缓冲。 当字符数超过1024个时,进行IO操作 使用换行符时候进行IO 全缓冲 在使用全缓冲的情况下,当数据填满整个缓冲区之后才进行实际的IO操作。对于驻留在磁盘上的文件的读写通常是使用全缓冲。通常如果不给文件流指定缓冲区的情况下,标准IO函数会首先调用malloc函数获取所需要的缓冲区。

Tinyhttpd源码解析

参考文档 https://jacktang816.github.io/post/tinyhttpdread/ 执行过程 HTTP HTTP请求头 当然,下面是一个带有 \r\n 行结尾的 HTTP 请求头示例: 1 2 3 4 5 6 7 8 9 GET /index.html HTTP/1.1\r\n Host: www.example.com\r\n User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n Accept-Language: en-US,en;q=0.5\r\n Accept-Encoding: gzip, deflate\r\n Connection: keep-alive\r\n Upgrade-Insecure-Requests: 1\r\n \r\n 解释 每一行都是一个 HTTP 头字段,使用 \r\n(回车符和换行符)来表示行结束。 最后一行的 \r\n 表示头部结束,之后的内容(如果有)是请求的主体。 分解示例 请求行: 1 GET /index.html HTTP/1.1\r\n GET 是 HTTP 方法。 /index.html 是请求的路径。 HTTP/1.1 是 HTTP 版本。 头字段:

C Intptr_t类型

intptr_t 是一种在 C 和 C++ 标准库中定义的整数类型。它是专门设计用来存储指针的整数类型,确保能够存储任何指针的整数值。这个类型定义在 <stdint.h> 头文件中。 详细解释 定义: intptr_t 是一个有符号整数类型,能够存储任何指针转换成的整数值。 对应的无符号类型是 uintptr_t。 用途: 通常用于需要将指针值存储为整数或者从整数恢复指针值的场景。 在进行指针与整数之间的转换时,使用 intptr_t 可以确保程序的可移植性和类型的安全性。 头文件: 在 C 中:#include <stdint.h> 在 C++ 中:#include <cstdint> 示例 下面是一个简单的示例,展示如何使用 intptr_t 类型: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio.h> #include <stdint.h> int main() { int a = 42; int *p = &a; // 将指针转换为整数 intptr_t int_value = (intptr_t)p; printf("Pointer as integer: %ld\n", (long)int_value); // 将整数转换回指针 int *new_p = (int *)int_value; printf("Value through new pointer: %d\n", *new_p); return 0; } 解释 int a = 42; 定义一个整数变量 a。 int *p = &a; 定义一个指针 p,指向变量 a。 (intptr_t)p 将指针 p 转换为整数类型 intptr_t。 printf("Pointer as integer: %ld\n", (long)int_value); 输出指针转换后的整数值。 (int *)int_value 将整数值 int_value 转换回指针类型。 printf("Value through new pointer: %d\n", *new_p); 输出通过新指针 new_p 访问的值。 使用 intptr_t 和 uintptr_t 可以确保指针和整数之间的转换在不同平台上都是安全和可移植的。
0%