面试题答案
一键面试数组内存分配机制
- 初始化时内存占用:
- Go语言中数组的长度是固定的,一旦声明,其长度就不可改变。当数组被初始化时,会在内存中分配一块连续的内存空间,用来存储数组的所有元素。例如,
var arr [5]int
声明了一个长度为5的整数数组,系统会一次性分配能够容纳5个int
类型元素的连续内存空间。这个内存空间的大小是固定的,由数组的长度和元素类型共同决定。如果元素类型是int
,在64位系统上每个int
占8字节,那么这个数组将占用5 * 8 = 40
字节的内存。
- Go语言中数组的长度是固定的,一旦声明,其长度就不可改变。当数组被初始化时,会在内存中分配一块连续的内存空间,用来存储数组的所有元素。例如,
- 元素增减时内存变化:由于数组长度固定,不存在元素增减的情况。如果尝试访问超出数组长度的索引,会导致运行时错误(越界错误)。所以数组内存一旦分配,在其生命周期内不会因为所谓的“元素增减”而改变内存大小。
切片内存分配机制
- 初始化时内存占用:
- 切片是基于数组的动态数据结构,它本身是一个结构体,包含三个字段:指向底层数组的指针、切片的长度(
len
)和切片的容量(cap
)。当通过make
函数或字面量初始化切片时,会先分配一个底层数组,然后切片指向这个底层数组。例如,s := make([]int, 5, 10)
会创建一个长度为5、容量为10的int
类型切片。这里会先分配一个能够容纳10个int
类型元素的底层数组(在64位系统上占用10 * 8 = 80
字节内存),然后切片s
指向这个底层数组的前5个元素,其长度为5,容量为10。如果使用字面量初始化,如ss := []int{1, 2, 3}
,会创建一个长度和容量都为3的切片,同时分配一个能容纳3个int
元素的底层数组(占用3 * 8 = 24
字节内存)。
- 切片是基于数组的动态数据结构,它本身是一个结构体,包含三个字段:指向底层数组的指针、切片的长度(
- 元素增减时内存变化:
- 增加元素:当向切片中添加元素(使用
append
函数),如果当前切片的长度小于容量(len < cap
),则直接在底层数组未使用的空间中添加新元素,不会重新分配内存。例如,上述容量为10长度为5的切片s
,当添加元素时,只要总元素个数不超过10,就会在底层数组剩余空间添加。但是,当添加元素后导致切片长度超过容量(len > cap
)时,Go语言会重新分配内存。通常会分配一个更大的底层数组,一般新容量是原容量的2倍(如果原容量小于1024),如果原容量大于等于1024,则新容量会增加原容量的1/4。然后将原切片的所有元素复制到新的底层数组中,再将新元素添加进去。 - 减少元素:切片本身并没有直接减少元素后释放底层数组内存的机制。例如通过切片操作(如
s = s[:3]
)缩短切片长度,底层数组依然存在,占用的内存并不会立即释放。只有当没有任何切片指向这个底层数组时,垃圾回收器才会回收该底层数组占用的内存。
- 增加元素:当向切片中添加元素(使用