Golang逃逸分析

问题: golang函数传参是不是应该和c一样,尽量不要直接传结构体,而是要传结构体指针? 逃逸分析 逃逸分析指的是,在计算机语言编译器优化原理中,分析指针动态范围的方法,和编译器优化原理的指针分析和外形分析相关联。当变量(或者对象)在方法中被分配后,其指针有可能被返回或者被全局引用,这种现象就是指针(或引用)的逃逸(Escape)。 其实在java概念中有一个误解 — new出来的东西都在堆上,栈上存的是它的引用。 这句话在现代JVM上有问题,就是因为逃逸分析机制。简单来说,就是JVM的逃逸分析会在运行时(runtime)检测当前方法栈帧(frame)内new出来的对象的引用,是否被传出当前的栈帧。如果传出,就会发生逃逸,没有传出则不会。对于未发生逃逸的变量,则会直接在栈上分配内存。因为栈上内存由在函数返回时自动回收,而堆上的的内存需要gc去回收,如果程序中有大量逃逸的对象,那么势必会增加gc的压力。 1 2 3 4 5 6 7 8 9 10 public void test(){ List<Integer> a = new ArrayList<>(); a.add(1); // a 未逃逸,在栈上分配 } public List<Integer> test1(){ List<Integer> a = new ArrayList<>(); a.add(1); return a // 发生逃逸,因此分配在堆上 } 区别 不同于JVM运行时的逃逸分析,Golang的逃逸分析是在编译期完成。 golang的逃逸分析只针对指针。一个值引用变量如果没有被取址,那么它永远不可能逃逸。 go version go1.13.4 darwin/amd64 验证某个函数的变量是否发生逃逸的方法: go run -gcflags “-m -l” (-m打印逃逸分析信息,-l禁止内联编译) ...

November 23, 2020 · 4 min · 852 words · Me

Design Pattern: Overview

Design pattern Builder Pattern scenario:build complicated object 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 package msg type Message struct { Header *Header Body *Body } type Header struct { SrcAddr string SrcPort uint64 DestAddr string DestPort uint64 Items map[string]string } type Body struct { Items []string } // Message对象的复杂对象 type builder struct{ once *sync.Once msg *Message } // 返回Builder对象 func Builder() *builder{ return &builder{ once: &sync.Once{}, msg: &Message{Header: &Header{}, Body: &Body{}}, } } func (b *builder) WithSrcAddr(srcAddr string) *builder{ b.msg.Header.SrcAddr = srcAddr return b } //...... func (b *builder) WithHeaderItem(key, value string) *builder{ //map只初始化一次 b.once.Do(func(){ b.msg.Header.Items = make(map[string]string) }) b.msg.Header.Items[key] = value return b } func (b *builder) WithBodyItem(record string) *builder{ b.msg.Body.Items = append(b.msg.Body.Items, record) return b } func (b *builder) Build() *Message{ return b.msg } Test code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package test func TestMessageBuilder(t *testing.T) { // 使用消息建造者进行对象创建 message := msg.Builder(). WithSrcAddr("192.168.0.1"). WithSrcPort(1234). WithDestAddr("192.168.0.2"). WithDestPort(8080). WithHeaderItem("contents", "application/json"). WithBodyItem("record1"). WithBodyItem("record2"). Build() if message.Header.SrcAddr != "192.168.0.1" { t.Errorf("expect src address 192.168.0.1, but actual %s.", message.Header.SrcAddr) } if message.Body.Items[0] != "record1" { t.Errorf("expect body item0 record1, but actual %s.", message.Body.Items[0]) } } Abstract Factory Pattern ...

November 11, 2020 · 6 min · 1098 words · Me