面试题答案
一键面试性能优化和内存管理策略
- 字符串拼接:
- 使用
strings.Builder
代替+
操作符。+
操作符在每次拼接时都会创建新的字符串,导致大量的内存分配和复制。而strings.Builder
预先分配足够的空间,在内部缓冲区进行拼接,完成后一次性生成最终字符串,减少内存分配次数。例如:
var sb strings.Builder for _, str := range []string{"a", "b", "c"} { sb.WriteString(str) } result := sb.String()
- 使用
- 字符串格式化:
- 使用
fmt.Sprintf
时,尽量复用缓冲区。fmt
包中有fmt.Fprintf
等函数可以将格式化结果写入io.Writer
。可以创建一个bytes.Buffer
作为io.Writer
,这样可以避免每次格式化都分配新的字符串。例如:
var buf bytes.Buffer fmt.Fprintf(&buf, "Hello, %s!", "world") result := buf.String()
- 使用
- 字符串切割:
- 避免使用
strings.Split
等会产生大量中间字符串的函数,尤其是在高并发频繁切割场景下。这些函数会为每个切割后的子串分配新的内存。
- 避免使用
使用 io.Reader
和 bufio.Scanner
优化字符串切割
-
固定长度子串切割:
- 将长字符串转换为
strings.Reader
,它实现了io.Reader
接口。 - 使用
bufio.Scanner
来逐块读取字符串。bufio.Scanner
内部有缓冲区,在读取时可以减少系统调用次数,提高性能。 - 配置
bufio.Scanner
的分隔符和缓冲区大小。例如,要切割为固定长度为n
的子串,可以设置一个自定义的分隔符函数,每次读取n
个字节。
package main import ( "bufio" "fmt" "strings" ) func main() { longStr := "abcdefghijklmnopqrstuvwxyz" reader := strings.NewReader(longStr) scanner := bufio.NewScanner(reader) n := 3 // 固定长度 scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { return 0, nil, nil } if len(data) < n { n = len(data) } return n, data[0:n], nil }) for scanner.Scan() { fmt.Println(string(scanner.Bytes())) } }
在上述代码中,
scanner.Split
函数定义了切割逻辑,每次返回固定长度n
的子串。scanner.Scan
会按此逻辑逐块读取字符串,减少了不必要的内存分配。同时,bufio.Scanner
的内部缓冲区机制也优化了性能。 - 将长字符串转换为