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

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

问题描述

众所周知,在Java中,二维数组是多维一维数组.这意味着那些一维数组在内存中不连续.

In Java, as we known, two dimensional array is multi one-dimensional array. That means those one-dimensional arrays not consecutive on memory.

相反,在C语言中,二维数组实际上是尺寸为 total_row * total_column 的一维数组.因为Go语言使用了C语言中的许多概念.所以我的问题是:Go中的二维数组的内存表示看起来像C还是Java?

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?

推荐答案

在Go中,切片经常被误认为数组,所以我对两者都回答.

In Go, slices are often mistaken for arrays, so I answer regarding both.

引用规范:数组类型:

数组类型始终是一维的,但可以组成多维类型.

Array types are always one-dimensional but may be composed to form multi-dimensional types.

您的答案清晰明了.但是答案不只是因为数组是Go中的值,它们也不像切片一样是描述符(标头).

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.

看这个简单的例子:

x := [5][5]byte{}
fmt.Println(&x[0][3])
fmt.Println(&x[0][4])
fmt.Println(&x[1][0])

输出(在进入游乐场上尝试):

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.

检查数组大小:

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.

在切片的情况下也是如此:多维切片是切片的切片. 规范:切片类型:

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.

请参见以下示例:

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]))

输出(在进入游乐场上尝试):

2 2000
1000 2000

xy多维切片总共有2000个元素(2000个字节),但是x仅存储2个切片,每个切片都具有1000个元素,而y存储1000个切片,每个元素都有2个元素.

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.

这意味着x需要2条带头,而y需要1000条带头(对于元素,xy本身为+1)!

This means x requires 2 slice headers while y requires 1000 slice headers (for the elements, +1 for x and y themselves)!

切片标头由 reflect.SliceHeader :

A slice header is represented by reflect.SliceHeader:

type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

在32位体系结构上,切片标头的大小为12个字节,在64位体系结构上,其为24个字节.因此,如果x的32位arch元素需要2,000字节加上2x12字节的内存,即 2,024字节,而y元素则需要2,000字节加上1,000 * 12的 14,000字节.

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.

如本例所示:

x := make([][]byte, 2)
x[0] = []byte{1, 2}
x[1] = []byte{1, 2, 3, 4}
fmt.Println(x[0])
fmt.Println(x[1])

输出(在转到操场上尝试):

[1 2]
[1 2 3 4]


如果您还没有读过,建议您: The Go Blog:数组,切片(和字符串): '追加'

这篇关于二维数组的内存表示如何的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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