github.com/fjl/memsize@v0.0.2/memsize_test.go (about) 1 package memsize 2 3 import ( 4 "testing" 5 "unsafe" 6 ) 7 8 const ( 9 sizeofSlice = unsafe.Sizeof([]byte{}) 10 sizeofMap = unsafe.Sizeof(map[string]string{}) 11 sizeofInterface = unsafe.Sizeof((interface{})(nil)) 12 sizeofString = unsafe.Sizeof("") 13 sizeofWord = unsafe.Sizeof(uintptr(0)) 14 sizeofChan = unsafe.Sizeof(make(chan struct{})) 15 ) 16 17 type ( 18 struct16 struct { 19 x, y uint64 20 } 21 structptr struct { 22 x uint32 23 cld *structptr 24 } 25 structuint32ptr struct { 26 x *uint32 27 } 28 structmultiptr struct { 29 s1 *structptr 30 u1 *structuint32ptr 31 s2 *structptr 32 u2 *structuint32ptr 33 s3 *structptr 34 u3 *structuint32ptr 35 } 36 structarrayptr struct { 37 x *uint64 38 a [10]uint64 39 } 40 structiface struct { 41 s *struct16 42 x interface{} 43 } 44 struct64array struct{ array64 } 45 structslice struct{ s []uint32 } 46 structstring struct{ s string } 47 structloop struct{ s *structloop } 48 structptrslice struct{ s *structslice } 49 array64 [64]byte 50 ) 51 52 func TestTotal(t *testing.T) { 53 tests := []struct { 54 name string 55 v interface{} 56 want uintptr 57 }{ 58 { 59 name: "struct16", 60 v: &struct16{}, 61 want: 16, 62 }, 63 { 64 name: "structptr_nil", 65 v: &structptr{}, 66 want: 2 * sizeofWord, 67 }, 68 { 69 name: "structptr", 70 v: &structptr{cld: &structptr{}}, 71 want: 2 * 2 * sizeofWord, 72 }, 73 { 74 name: "structptr_loop", 75 v: func() *structptr { 76 v := &structptr{} 77 v.cld = v 78 return v 79 }(), 80 want: 2 * sizeofWord, 81 }, 82 { 83 name: "structmultiptr_loop", 84 v: func() *structmultiptr { 85 v1 := &structptr{x: 1} 86 v2 := &structptr{x: 2, cld: v1} 87 return &structmultiptr{s1: v1, s2: v1, s3: v2} 88 }(), 89 want: 6*sizeofWord /* structmultiptr */ + 2*2*sizeofWord, /* structptr */ 90 }, 91 { 92 name: "structmultiptr_interior", 93 v: func() *structmultiptr { 94 v1 := &structptr{x: 1} 95 v2 := &structptr{x: 2} 96 return &structmultiptr{ 97 // s1 is scanned before u1, which has a reference to a field of s1. 98 s1: v1, 99 u1: &structuint32ptr{x: &v1.x}, 100 // This one goes the other way around: u2, which has a reference to a 101 // field of s3 is scanned before s3. 102 u2: &structuint32ptr{x: &v2.x}, 103 s3: v2, 104 } 105 }(), 106 want: 6*sizeofWord /* structmultiptr */ + 2*2*sizeofWord /* structptr */ + 2*sizeofWord, /* structuint32ptr */ 107 }, 108 { 109 name: "struct64array", 110 v: &struct64array{}, 111 want: 64, 112 }, 113 { 114 name: "structptrslice", 115 v: &structptrslice{&structslice{s: []uint32{1, 2, 3}}}, 116 want: sizeofWord + sizeofSlice + 3*4, 117 }, 118 { 119 name: "array_unadressable", 120 v: func() *map[[3]uint64]struct{} { 121 v := map[[3]uint64]struct{}{ 122 {1, 2, 3}: struct{}{}, 123 } 124 return &v 125 }(), 126 want: sizeofMap + 3*8, 127 }, 128 { 129 name: "structslice", 130 v: &structslice{s: []uint32{1, 2, 3}}, 131 want: sizeofSlice + 3*4, 132 }, 133 { 134 name: "structloop", 135 v: func() *structloop { 136 v := new(structloop) 137 v.s = v 138 return v 139 }(), 140 want: sizeofWord, 141 }, 142 { 143 name: "array64", 144 v: &array64{}, 145 want: 64, 146 }, 147 { 148 name: "byteslice", 149 v: &[]byte{1, 2, 3}, 150 want: sizeofSlice + 3, 151 }, 152 { 153 name: "slice3_ptrval", 154 v: &[]*struct16{{}, {}, {}}, 155 want: sizeofSlice + 3*sizeofWord + 3*16, 156 }, 157 { 158 name: "map0", 159 v: &map[uint64]uint64{}, 160 want: sizeofMap, 161 }, 162 { 163 name: "map3", 164 v: &map[uint64]uint64{1: 1, 2: 2, 3: 3}, 165 want: sizeofMap + 3*8 /* keys */ + 3*8, /* values */ 166 }, 167 { 168 name: "map3_ptrval", 169 v: &map[uint64]*struct16{1: {}, 2: {}, 3: {}}, 170 want: sizeofMap + 3*8 /* keys */ + 3*sizeofWord /* value pointers */ + 3*16, /* values */ 171 }, 172 { 173 name: "map3_ptrkey", 174 v: &map[*struct16]uint64{{x: 1}: 1, {x: 2}: 2, {x: 3}: 3}, 175 want: sizeofMap + 3*sizeofWord /* key pointers */ + 3*16 /* keys */ + 3*8, /* values */ 176 }, 177 { 178 name: "map_interface", 179 v: &map[interface{}]interface{}{"aa": uint64(1)}, 180 want: sizeofMap + sizeofInterface + sizeofString + 2 /* key */ + sizeofInterface + 8, /* value */ 181 }, 182 { 183 name: "pointerpointer", 184 v: func() **uint64 { 185 i := uint64(0) 186 p := &i 187 return &p 188 }(), 189 want: sizeofWord + 8, 190 }, 191 { 192 name: "structstring", 193 v: &structstring{"123"}, 194 want: sizeofString + 3, 195 }, 196 { 197 name: "slices_samearray", 198 v: func() *[3][]byte { 199 backarray := [64]byte{} 200 return &[3][]byte{ 201 backarray[16:], 202 backarray[4:16], 203 backarray[0:4], 204 } 205 }(), 206 want: 3*sizeofSlice + 64, 207 }, 208 { 209 name: "slices_nil", 210 v: func() *[2][]byte { 211 return &[2][]byte{nil, nil} 212 }(), 213 want: 2 * sizeofSlice, 214 }, 215 { 216 name: "slices_overlap_total", 217 v: func() *[2][]byte { 218 backarray := [32]byte{} 219 return &[2][]byte{backarray[:], backarray[:]} 220 }(), 221 want: 2*sizeofSlice + 32, 222 }, 223 { 224 name: "slices_overlap", 225 v: func() *[4][]uint16 { 226 backarray := [32]uint16{} 227 return &[4][]uint16{ 228 backarray[2:4], 229 backarray[10:12], 230 backarray[20:25], 231 backarray[:], 232 } 233 }(), 234 want: 4*sizeofSlice + 32*2, 235 }, 236 { 237 name: "slices_overlap_array", 238 v: func() *struct { 239 a [32]byte 240 s [2][]byte 241 } { 242 v := struct { 243 a [32]byte 244 s [2][]byte 245 }{} 246 v.s[0] = v.a[2:4] 247 v.s[1] = v.a[5:8] 248 return &v 249 }(), 250 want: 32 + 2*sizeofSlice, 251 }, 252 { 253 name: "interface", 254 v: &[2]interface{}{uint64(0), &struct16{}}, 255 want: 2*sizeofInterface + 8 + 16, 256 }, 257 { 258 name: "interface_nil", 259 v: &[2]interface{}{nil, nil}, 260 want: 2 * sizeofInterface, 261 }, 262 { 263 name: "structiface_slice", 264 v: &structiface{x: make([]byte, 10)}, 265 want: sizeofWord + sizeofInterface + sizeofSlice + 10, 266 }, 267 { 268 name: "structiface_pointer", 269 v: func() *structiface { 270 s := &struct16{1, 2} 271 return &structiface{s: s, x: &s.x} 272 }(), 273 want: sizeofWord + 16 + sizeofInterface, 274 }, 275 { 276 name: "empty_chan", 277 v: func() *chan uint64 { 278 c := make(chan uint64) 279 return &c 280 }(), 281 want: sizeofChan, 282 }, 283 { 284 name: "empty_closed_chan", 285 v: func() *chan uint64 { 286 c := make(chan uint64) 287 close(c) 288 return &c 289 }(), 290 want: sizeofChan, 291 }, 292 { 293 name: "empty_chan_buffer", 294 v: func() *chan uint64 { 295 c := make(chan uint64, 10) 296 return &c 297 }(), 298 want: sizeofChan + 10*8, 299 }, 300 { 301 name: "chan_buffer", 302 v: func() *chan uint64 { 303 c := make(chan uint64, 10) 304 for i := 0; i < 8; i++ { 305 c <- 0 306 } 307 return &c 308 }(), 309 want: sizeofChan + 10*8, 310 }, 311 { 312 name: "closed_chan_buffer", 313 v: func() *chan uint64 { 314 c := make(chan uint64, 10) 315 for i := 0; i < 8; i++ { 316 c <- 0 317 } 318 close(c) 319 return &c 320 }(), 321 want: sizeofChan + 10*8, 322 }, 323 { 324 name: "chan_buffer_escan", 325 v: func() *chan *struct16 { 326 c := make(chan *struct16, 10) 327 for i := 0; i < 8; i++ { 328 c <- &struct16{x: uint64(i)} 329 } 330 return &c 331 }(), 332 want: sizeofChan + 10*sizeofWord + 8*16, 333 }, 334 { 335 name: "closed_chan_buffer_escan", 336 v: func() *chan *struct16 { 337 c := make(chan *struct16, 10) 338 for i := 0; i < 8; i++ { 339 c <- &struct16{x: uint64(i)} 340 } 341 close(c) 342 return &c 343 }(), 344 want: sizeofChan + 10*sizeofWord + 8*16, 345 }, 346 { 347 name: "nil_chan", 348 v: func() *chan *struct16 { 349 var c chan *struct16 350 return &c 351 }(), 352 want: sizeofChan, 353 }, 354 } 355 for _, test := range tests { 356 t.Run(test.name, func(t *testing.T) { 357 size := Scan(test.v) 358 if size.Total != test.want { 359 t.Errorf("total=%d, want %d", size.Total, test.want) 360 t.Logf("\n%s", size.Report()) 361 } 362 }) 363 } 364 }