├── images ├── memorystruct1.png └── memorystruct2.png ├── main.go └── README.md /images/memorystruct1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tkanos/optimizing-memory-by-ordering-struct-by-type/HEAD/images/memorystruct1.png -------------------------------------------------------------------------------- /images/memorystruct2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tkanos/optimizing-memory-by-ordering-struct-by-type/HEAD/images/memorystruct2.png -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | type myStruct struct { 9 | myInt bool // 1 byte 10 | myFloat float64 // 8 bytes 11 | myBool int32 // 4 bytes 12 | } 13 | 14 | type myStructOptimized struct { 15 | myFloat float64 // 8 bytes 16 | myInt int32 // 4 bytes 17 | myBool bool // 1 byte 18 | } 19 | 20 | func main() { 21 | a := myStruct{} 22 | b := myStructOptimized{} 23 | 24 | fmt.Println(unsafe.Sizeof(a)) // unordered 24 bytes 25 | fmt.Println(unsafe.Sizeof(b)) // ordered 16 bytes 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # How to organize the go struct, in order to save memory. 2 | 3 | In this article I want to explain you how the memory works internally in a 64 bit architecture, when you instantiate a struct. (You can play with the code https://play.golang.org/p/cUgB54yCpL ) 4 | 5 | ## How memory works internally : 6 | 7 | When you have a struct like this one : 8 | ```golang 9 | type myStruct struct { 10 | myBool bool // 1 byte 11 | myFloat float64 // 8 bytes 12 | myInt int32 // 4 bytes 13 | } 14 | ``` 15 | 16 | As you see a boolean takes 1 byte, a float64 8 bytes, and an int32 4 bytes. 17 | But the memory allocates consecutive packet of 8 bytes. So instead of taking 1 + 8 + 4 = 13 bytes. This struct will takes : 24 bytes 18 | ```golang 19 | a := myStruct{} 20 | fmt.Println(unsafe.Sizeof(a)) // 24 bytes 21 | ``` 22 | Because in memory we will have : 23 | 24 | ![Struct in memory](/images/memorystruct1.png) 25 | 26 | So 8 + 8 + 8 = 24 bytes 27 | 28 | ## How to optimize : 29 | It’s possible to optimize, ordering the struct by bytes taken : 30 | ```golang 31 | type myStructOptimized struct { 32 | myFloat float64 // 8 bytes 33 | myBool bool // 1 byte 34 | myInt int32 // 4 bytes 35 | } 36 | ``` 37 | This new struct ordered will take now : 38 | ```golang 39 | b := myStructOptimized{} 40 | fmt.Println(unsafe.Sizeof(b)) // ordered 16 bytes 41 | ``` 42 | 16 bytes, because in memory it will be allocated like that (https://play.golang.org/p/gmkrt6X7aM) : 43 | 44 | ![Struct in memory](/images/memorystruct2.png) 45 | 46 | 8 + 8 = 16 bytes 47 | 48 | As you can see, there are a padding to respect the data alignment, (https://en.wikipedia.org/wiki/Data_structure_alignment), So it means that in some case the data is not optimally word-aligned (depending on many things processor, cache memory, virtual memory) and it can sometimes slower the application, so benchmark everything :D 49 | 50 | ### Links : 51 | https://play.golang.org/p/cUgB54yCpL 52 | https://github.com/Tkanos/optimizing-memory-by-ordering-struct-by-type 53 | http://www.catb.org/esr/structure-packing/ 54 | https://en.wikipedia.org/wiki/Data_structure_alignment 55 | --------------------------------------------------------------------------------