1.为什么gjson库会比内置库encoding/json快?(其他功能忽略,只说unsafe)

使用unsafe.Pointer破坏类型系统并读写任意内存,主要用于转换各种类型。
image.png
而笔者去看了一下encoding/json库,并没有发现用到unsafe。
image.png
看一组基准测试数据:
image.png
gjson的getBytes方法源码,使用unsafe。
image.png
https://github.com/tidwall/gjson
easyjson的readme:
image.png
unsafe是官方提议,不安全,要小心使用。除非用来管理内存布局使用。
为什么可以做到这么快?因为使用unsafe包对内存直接进行读写, 而unsafe内置库是会绕开内存安全机制的。
官方提供:unsafe package - unsafe - Go Packages

2.如何理解unsafe 包之内存布局?

需要了解的概念和unsafe API哦:

  • func Alignof(x ArbitraryType ) uintptr 对齐系数或者对齐倍数,每个字段在内存中的偏移量是对齐值的倍数
  • func Sizeof(x ArbitraryType ) uintptr内存大小,2^n。如果偏移量不够,则补齐。例如某struct结构体,字段A占1个字节、字段A4个字节,则大小为1+3+4=8。
  • 偏移量:计算机汇编语言,是指把存储单元的实际地址与其所在段的段地址之间的距离称为段内偏移,也称为“有效地址或偏移量”;
  • func Offsetof(x ArbitraryType ) uintptr 偏移量大小
  • 对齐值,此处golang的最大偏移量和内存大小有关,不同电脑有不同的值,我的是8.

不同的struct字段编排,所占有的内存不同。代码如下:

  1. package main
  2. import (
  3. "fmt"
  4. "unsafe"
  5. )
  6. // 内存对齐影响struct的大小
  7. // struct的字段顺序影响struct的大小
  8. type user1 struct {
  9. b byte
  10. i int32
  11. j int64
  12. }
  13. type user2 struct {
  14. b byte
  15. j int64
  16. i int32
  17. }
  18. type user3 struct {
  19. i int32
  20. b byte
  21. j int64
  22. }
  23. type user4 struct {
  24. i int32
  25. j int64
  26. b byte
  27. }
  28. type user5 struct {
  29. j int64
  30. b byte
  31. i int32
  32. }
  33. type user6 struct {
  34. j int64
  35. i int32
  36. b byte
  37. }
  38. // 内存对齐影响struct的大小
  39. // struct的字段顺序影响struct的大小
  40. func main() {
  41. var u1 user1 // u1 size is 16
  42. var u2 user2 // u2 size is 24
  43. var u3 user3 // u3 size is 16
  44. var u4 user4 // u4 size is 24
  45. var u5 user5 // u5 size is 16
  46. var u6 user6 // u6 size is 16
  47. fmt.Println("u1 size is ", unsafe.Sizeof(u1))
  48. fmt.Println("u2 size is ", unsafe.Sizeof(u2))
  49. fmt.Println("u3 size is ", unsafe.Sizeof(u3))
  50. fmt.Println("u4 size is ", unsafe.Sizeof(u4))
  51. fmt.Println("u5 size is ", unsafe.Sizeof(u5))
  52. fmt.Println("u6 size is ", unsafe.Sizeof(u6))
  53. }

image.png
发现了,最后不同u1和u2内存大小不同。
结论:
1.内存对齐影响struct的大小(因为会补足到8的倍数)
2.struct的字段顺序影响struct的大小(因为)
所以有时候合理的字段顺序可以减少内存的开销