什么是二维数组的内存表示? [英] What is two dimensional array's memory representation?

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

问题描述

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

In Java, 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 的概念.

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.

所以我的问题是:Go 中二维数组的内存表示看起来像 C 还是 Java?

So my question is: does two dimensional array's memory representation in Go look like C or Java?

推荐答案

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

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

输出(在 Go Playground 上试试):

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.

检查数组的大小:

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

输出(在 Go Playground 上试试):

Output (try it on the Go Playground):

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 个切片头(对于元素,+1 代表 xy 本身)!

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

输出(在 Go Playground 上试试):

Output (try it on the Go Playground):

[1 2]
[1 2 3 4]

<小时>

如果您还没有阅读,推荐:Go 博客:数组、切片(和字符串):'附加'

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

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