面试题答案
一键面试闭包对性能的影响
- 内存占用:
- 闭包会持有外部变量的引用,即使外部变量的作用域已经结束,只要闭包还在使用,外部变量就不会被释放,从而导致额外的内存占用。
- 例如:
package main
import "fmt"
func outer() func() {
data := make([]int, 1000000)
inner := func() {
fmt.Println(len(data))
}
return inner
}
在上述代码中,outer
函数返回一个闭包inner
,inner
持有了data
切片的引用。即使outer
函数执行完毕,data
切片由于被闭包引用,依然不会被释放,占用额外内存。
2. 垃圾回收:
- 因为闭包持有外部变量引用,垃圾回收器(GC)不能轻易回收这些被引用的变量。这可能导致垃圾回收延迟,影响程序整体性能。
- 例如,假设在一个高并发场景下,大量创建类似上述
outer
函数返回的闭包,并且这些闭包长时间存活,就会导致很多本可以被回收的变量无法及时回收,造成内存堆积。
优化策略
- 减少不必要的外部变量引用:
- 尽量只在闭包中引用真正需要的变量,避免引入过多不必要的外部变量。
- 例如:
package main
import "fmt"
func outer() func(int) {
base := 10
inner := func(x int) {
result := base + x
fmt.Println(result)
}
return inner
}
这里闭包inner
只引用了base
变量,如果base
变量是一个很大的结构体,而闭包实际只需要其中的一个字段,那么可以只传入这个字段,而不是整个结构体,以减少内存占用。
2. 及时释放闭包:
- 当闭包不再需要使用时,及时将其设置为
nil
,以便垃圾回收器能够回收相关资源。 - 例如:
package main
import "fmt"
func main() {
f := outer()
f()
f = nil // 及时释放闭包
}
func outer() func() {
data := make([]int, 1000000)
inner := func() {
fmt.Println(len(data))
}
return inner
}
在上述代码中,当使用完闭包f
后,将其设置为nil
,这样垃圾回收器就有机会回收data
切片占用的内存。