Go:二维数组的内存表示如何 [英] Go: How is two dimensional array's memory representation

查看:146
本文介绍了Go:二维数组的内存表示如何的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Java中,如我​​们所知,二维数组是多维的一维数组。这意味着那些一维数组在内存中不连续。



相反,在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 元素,而 y 存储 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)
x [0] = [] byte {1,2}
x [1] = [ ]字节{1,2,3,4}
fmt.Println(x [0])
fmt.Println(x [1])$ ​​b $ b
pre>

输出(在 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 and y multidimensional slices have 2000 elements total (2000 bytes), but x stores 2 slices only, each having 1000 elements, while y stores 1000 slices, each having 2 elements.

This means x requires 2 slice headers while y requires 1000 slice headers (for the elements, +1 for x and y 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 of y 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆