Go:二维数组的内存表示如何 [英] Go: How is two dimensional array's memory representation
问题描述
相反,在C中,二维数组实际上是一维数组,大小为 total_row * total_column 。因为Go语言使用了很多C的概念。所以我的问题是:Go中的二维数组的内存表示看起来像是在C还是Java?
在Go中,切片经常被误认为 arrays ,所以我回答了两个问题。
阵列
引用 spec:数组类型
$ b
数组类型始终是一维,但可以组成多维类型。 b
您的答案清楚明了。但是答案并不仅仅是因为数组是Go中的值,它们不像描述符(标题)一样。
请看这个简单的例子:
x:= [5] [5] byte {}
fmt.Println(& x [0] [3])
fmt.Println(& x [0] [4])
fmt.Println(& x [1] [0])
输出(在去游乐场试试):
0x10432203
0x10432204
0x10432205
正如您所看到的,为阵列分配和使用的内存是连续的:第二行从内存地址开始,后面是最后一个地址
检查数组大小:
fmt.Println(unsafe.Sizeof([4] [6] int {}))// 96
fmt.Println(unsafe.Sizeof([6] [4] int {}))// 96
切换行和列无关紧要,其大小相同。
切片
在切片的情况下也是如此:多维切片是一片切片。 规格:切片类型:
切片是底层数组的连续段的描述符,并提供对该数组中元素的编号序列的访问。
... <
与数组一样,切片始终是一维的,但可以组成更高维的对象。
切片是描述符,切片标头包含指向底层(后备)数组元素的指针,长度和容量。所以总的切片数量在内存使用方面很重要。
查看下面的例子:
为i:=范围x {
x [i] = make([] byte,1000)
}
fmt.Println(len(x),len(x)* len(x [0]))
y:= make([] [] byte,1000)
为i:=范围y {
y [i] = make([] byte,2)
}
fmt.Println(len(y),len(y)* len(y [0]))
输出(尝试在 Go Playground ):
2 2000
1000 2000
x
和 y
多维片具有2000个元素总数(2000字节),但 x
存储 2
切片,每个切片具有
存储 1000
元素,而 1000
切片,每个切片具有 2
元素。
这意味着 x
需要 2
切片标题 y
需要 1000
切片标题(对于元素, x
和 y
本身)!
切片标题由 reflect.SliceHeader
:
类型SliceHeader struct {
Data uintptr
Len int
Cap int
}
在32位体系结构中,片头的大小为12个字节,在64位体系结构中为24个字节。因此,如果 x
的32位元素元素需要2,000字节加上2x12字节的内存( 2,024字节),而元素 y
需要2,000字节加上1,000 * 12,它是 14,000字节。
还要注意多维切片可能包含不同长度的切片:
对于数组数组,内部数组的构造始终是相同的长度;然而,对于切片(或切片阵列),内部长度可以动态变化。此外,内部切片必须单独初始化。
像这样的例子:
x:= make([] [] byte,2)
pre>
x [0] = [] byte {1,2}
x [1] = [ ]字节{1,2,3,4}
fmt.Println(x [0])
fmt.Println(x [1])$ b $ b
输出(在 Go Playground ):
[1 2]
[1 2 3 4]
如果您还没有阅读,建议: The Go Blog:数组,切片(和字符串):'append'的机制
In Java, as we known, two dimensional array is multi one-dimensional array. That means those one-dimensional arrays not consecutive on memory.
In contrast, in C, two dimensional array in fact is one-dimensional array with size is total_row * total_column. Because Go language uses many concepts from C. So my question is: does two dimensional array's memory representation in Go look like in C or Java?
解决方案In Go, slices are often mistaken for arrays, so I answer regarding both.
Arrays
Quoting from the spec: Array types:
Array types are always one-dimensional but may be composed to form multi-dimensional types.
There you have your answer plain and clear. But the answer is not just that as arrays are values in Go, they are not descriptors (headers) like slices.
See this simple example:
x := [5][5]byte{} fmt.Println(&x[0][3]) fmt.Println(&x[0][4]) fmt.Println(&x[1][0])
Output (try it on the Go Playground):
0x10432203 0x10432204 0x10432205
As you can see, the memory allocated and used for the array is contiguous: the second row starts at a memory address that is the subsequent to the address of the last element of the first row.
Checking size of arrays:
fmt.Println(unsafe.Sizeof([4][6]int{})) // 96 fmt.Println(unsafe.Sizeof([6][4]int{})) // 96
It doesn't matter if you switch rows and columns, its size is the same.
Slices
The same applies in case of slices: a multidimensional slice is a slice of slices. Spec: Slice types:
A slice is a descriptor for a contiguous segment of an underlying array and provides access to a numbered sequence of elements from that array.
...
Like arrays, slices are always one-dimensional but may be composed to construct higher-dimensional objects.Slices are descriptors, a slice header contains a pointer to an element of an underlying (backing) array, a length and a capacity. So the number of total slices matters in terms of memory usage.
See this example:
x := make([][]byte, 2) for i := range x { x[i] = make([]byte, 1000) } fmt.Println(len(x), len(x)*len(x[0])) y := make([][]byte, 1000) for i := range y { y[i] = make([]byte, 2) } fmt.Println(len(y), len(y)*len(y[0]))
Output (try it on the Go Playground):
2 2000 1000 2000
Both
x
andy
multidimensional slices have 2000 elements total (2000 bytes), butx
stores2
slices only, each having1000
elements, whiley
stores1000
slices, each having2
elements.This means
x
requires2
slice headers whiley
requires1000
slice headers (for the elements, +1 forx
andy
themselves)!A slice header is represented by
reflect.SliceHeader
:type SliceHeader struct { Data uintptr Len int Cap int }
The size of a slice header on 32-bit architectures is 12 bytes, on 64 bit architectures its 24 bytes. So in case of 32-bit arch elements of
x
require 2,000 bytes plus 2x12 bytes in memory which is 2,024 bytes, while elements ofy
require 2,000 bytes plus 1,000*12 which is 14,000 bytes.Also note that elements of a multidimensional slice may contain slices with different lengths:
With arrays of arrays, the inner arrays are, by construction, always the same length; however with slices of slices (or arrays of slices), the inner lengths may vary dynamically. Moreover, the inner slices must be initialized individually.
Like in this example:
x := make([][]byte, 2) x[0] = []byte{1, 2} x[1] = []byte{1, 2, 3, 4} fmt.Println(x[0]) fmt.Println(x[1])
Output (try it on the Go Playground):
[1 2] [1 2 3 4]
If you haven't read, recommended: The Go Blog: Arrays, slices (and strings): The mechanics of 'append'
这篇关于Go:二维数组的内存表示如何的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!