MST

星途 面试题库

面试题:Go语言中数组与切片在内存分配上的区别

请详细阐述Go语言中数组与切片在内存分配方式上有哪些不同,并且举例说明这种差异会对程序产生怎样不同的表现。
35.8万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

内存分配方式不同

  1. 数组
    • 数组在Go语言中是固定长度的。其内存分配是在编译时就确定的,在栈上分配(如果数组大小比较小)或者在堆上分配(如果数组大小较大,具体由编译器优化决定)。一旦声明,数组的长度就不可改变,其占用的内存空间大小为数组元素类型大小乘以数组长度。例如声明var arr [5]int,那么arr就会占用5 * 8(假设int类型在当前平台占8字节)字节的连续内存空间。
  2. 切片
    • 切片是动态长度的。切片本身是一个结构体,它由三个部分组成:指向底层数组的指针、切片的长度和切片的容量。切片的内存分配涉及到两个层面,一是切片结构体本身的内存分配,它通常在栈上(如果切片变量是函数内局部变量等情况),二是底层数组的内存分配,底层数组的内存是在堆上分配的。当使用make函数创建切片时,如slice := make([]int, 5, 10),会在堆上分配一个能容纳10个int类型元素的数组,然后切片结构体指向这个数组,并且长度设为5,容量设为10。

对程序表现的不同影响举例

  1. 数组
    • 由于数组长度固定,在需要动态增加元素场景下会很不方便。例如:
package main

import "fmt"

func main() {
    var arr [5]int
    arr[0] = 1
    // 以下代码尝试增加元素会导致越界错误
    // arr[5] = 6 
    fmt.Println(arr)
}
  • 这里如果尝试向超出数组长度的位置赋值,会导致编译错误,这就限制了数组在动态场景下的使用。
  1. 切片
    • 切片的动态特性使其在需要动态增加元素时很方便。例如:
package main

import "fmt"

func main() {
    slice := make([]int, 0, 5)
    slice = append(slice, 1)
    slice = append(slice, 2)
    fmt.Println(slice)
}
  • 这里通过append函数可以方便地向切片中动态添加元素,即使最初切片的长度为0,随着append操作,切片会根据需要动态增长,底层数组也可能会重新分配内存以适应新的元素数量。如果当前容量不足以容纳新元素,会重新分配一个更大的底层数组,将原数组内容复制过去,然后再添加新元素。