机制:三色标记法 + 混合写屏障机制。 (栈无写屏障,堆有写屏障)
- 三色标记法。
- 初始对象全白
- 从根遍历。栈直接引用对象置黑,堆直接引用对象置灰。
- 遍历灰对象。引用置灰,当前灰置黑。 重复此步骤至无灰对象。
- 剩下的白对象回收。
- 混合写屏障机制。
- 栈:不用混合写屏障。新增对象直接置黑。 新增或删除引用(可以是堆上)不改变被引用对象颜色。
- 堆:启用混合写屏障。添加、删除的对象都标记为灰色。
2023年12月8日大约 2 分钟
代码为内部技术群大佬写的
package main
import (
"runtime"
"unsafe"
)
type markBits struct {
bytep *uint8
mask uint8
index uintptr
}
//go:linkname isMarked runtime.markBits.isMarked
func isMarked(m markBits) bool
//go:linkname spanOf runtime.spanOf
func spanOf(p uintptr) unsafe.Pointer
//go:linkname objIndex runtime.(*mspan).objIndex
func objIndex(s unsafe.Pointer, p uintptr) uintptr
//go:linkname allocBitsForIndex runtime.(*mspan).allocBitsForIndex
func allocBitsForIndex(s unsafe.Pointer, allocBitIndex uintptr) markBits
func allocBitsForAddr(p uintptr) markBits {
s := spanOf(p)
objIndex := objIndex(s, p)
return allocBitsForIndex(s, objIndex)
}
var ca [10]chan int
var pa [10]uintptr
func main() {
for i := 0; i < len(pa); i++ {
c := make(chan int, 10)
p := *(*uintptr)(unsafe.Pointer(&c))
c <- 1
c <- 2
c <- 3
ca[i] = c
pa[i] = p
}
for i := 0; i < len(pa); i++ {
if i%2 == 0 {
continue
}
ca[i] = nil
}
runtime.GC()
for i := 0; i < len(pa); i++ {
println(isMarked(allocBitsForAddr(pa[i])))
}
}
Redis怎么做分布式锁是老生常谈,但是之前没有注意一些细节,存在小隐患。
setnx前先获取对比判断,使用脚本原子性执行,先通过key获取,如果匹配id则获取到锁,如果没有正常加锁setnx。优雅退出:指HTTP服务在接到用户的退出指令后,停止接受新请求,对进行中的请求处理完成后再退出。
如下代码,main中启动http.ListenAndServe,在goroutine中signal.Notify监听退出信号,接口里sleep n秒模拟请求处理中。
测试:本地请求curl http://localhost:8080后,马上Ctrl + C。分别在处理函数里 sleep 3秒、8秒、20秒。看看区别。
json包中有个json.RawMessage其实就是[]byte的别名。
其主要是实现了Marshaler和Unmarshaler两个接口....
json.RawMessage 应用在判断情况是否解析,以及解析到什么结构上。例如:
type People struct {
Age uint8 `json:"age"`
Source uint8 `json:"source"`
Journey json.RawMessage `json:"journey"`
}
string和[]byte。利用指针直接构造的方式,可以避免拷贝开销,对大字符串有很好的效果。// 小于1.20
func String2Bytes(s string) []byte {
bs := struct {
string
Cap int
}{s, len(s)}
return *(*[]byte)(unsafe.Pointer(&bs))
}
func Bytes2String(bs []byte) string {
return *(*string)(unsafe.Pointer(&bs))
}
// 1.20
func String2Bytes(s string) []byte {
return unsafe.Slice(unsafe.StringData(s), len(s))
}
func Bytes2String(bs []byte) string {
return unsafe.String(&bs[0], len(bs))
}
package main
import (
"fmt"
"time"
)
type TM1 struct {
array [1024 * 64]byte
}
type TM2 struct {
array [1024*64 + 1]byte
}
func TestTM1() {
// 仅生成结构体
startTime := time.Now()
for i := 0; i < 10000; i++ {
s := TM1{}
s.array[0] = 1
}
fmt.Println("等于64KB结构体:", time.Since(startTime))
// 生成结构体指针
startTime = time.Now()
for i := 0; i < 10000; i++ {
s := new(TM1)
s.array[0] = 1
}
fmt.Println("等于64KB结构体指针:", time.Since(startTime))
}
func TestTM2() {
startTime := time.Now()
for i := 0; i < 10000; i++ {
s := TM2{}
s.array[0] = 1
}
fmt.Println("大于64KB结构体:", time.Since(startTime))
startTime = time.Now()
for i := 0; i < 10000; i++ {
s := new(TM2)
s.array[0] = 1
}
fmt.Println("大于64KB结构体指针:", time.Since(startTime))
}
func main() {
TestTM1()
TestTM2()
}