当前位置: 首页 > 面试题库 >

去垃圾会收集切片的一部分吗?

姜建德
2023-03-14
问题内容

如果我实现这样的队列…

package main

import(
    "fmt"
)

func PopFront(q *[]string) string {
    r := (*q)[0]
    *q = (*q)[1:len(*q)]
    return r
}

func PushBack(q *[]string, a string) {
    *q = append(*q, a)
}

func main() {
    q := make([]string, 0)

    PushBack(&q, "A")
    fmt.Println(q)
    PushBack(&q, "B")
    fmt.Println(q)
    PushBack(&q, "C")
    fmt.Println(q)

    PopFront(&q)
    fmt.Println(q)
    PopFront(&q)
    fmt.Println(q)      
}

…我得到的数组["A", "B", "C"]没有指向前两个元素的切片。由于切片的“开始”指针永远不会递减(AFAIK),因此永远无法访问这些元素。

Go的垃圾收集器足够聪明以释放它们吗?


问题答案:

切片只是描述符(类似于小型结构的数据结构),如果不对其进行引用,则会对其进行正确的垃圾回收。

另一方面,切片的基本数组(描述符指向该数组)在所有切片之间 共享 ,这些切片通过切片来 共享 :引用自Go语言规范:Slice
Types

切片一旦初始化,便始终与包含其元素的基础数组关联。因此,一个片与其阵列以及同一阵列的其他片共享存储。相反,不同的数组始终代表不同的存储。

因此,如果存在至少一个片,或保存数组的变量(如果通过对数组进行切片来创建片),则不会进行垃圾回收

关于此的官方声明:

安德鲁·格朗德(Andrew Gerrand)撰写的博客文章 Go
Slices:用法和内部

原理明确说明了这种行为:

如前所述,对切片进行重新切片不会复制基础数组。 完整的数组将保留在内存中,直到不再被引用为止。
有时,这可能导致程序仅需要一小部分数据时就将所有数据保存在内存中。

由于切片引用了原始数组, 因此只要将切片保留在垃圾收集器周围,就无法释放该数组

回到你的例子

虽然基础数组不会被释放,但是请注意,如果您将新元素添加到队列中,则内置append函数有时可能会分配新数组并将当前元素复制到新元素上,但是复制只会复制切片的元素而不是整个基础数组!当发生这种重新分配和复制时,如果没有其他引用,则可能会“回收”旧数组。

另一个非常重要的事情是,如果从前面弹出一个元素,则切片将被切片并且不包含对弹出元素的引用,但是由于基础数组仍包含该值,因此该值也将保留在内存中(而不是只是数组)。建议每当从队列(切片/数组)中弹出或删除一个元素时,
始终将其 (切片中其相应的元素) 置零, 这样该值就不会不必要地保留在内存中。如果您的分片包含指向大数据结构的指针,则这一点变得尤为重要。

func PopFront(q *[]string) string {
    r := (*q)[0]
    (*q)[0] = ""  // Always zero the removed element!
    *q = (*q)[1:len(*q)]
    return r
}

这里提到了Slice Tricks
Wiki页面:

删除但不保留订单

a[i] = a[len(a)-1]
a = a[:len(a)-1]

注意 如果元素的类型是一个 指针 或指针字段,其需要被垃圾收集一个结构,上述实施方式CutDelete有潜在的 存储器泄露
的问题:其值的一些元素仍然由切片引用a并因此不能集。



 类似资料:
  • Kubernetes 垃圾收集器的角色是删除指定的对象,这些对象曾经有但以后不再拥有 Owner 了。 注意:垃圾收集是 beta 特性,在 Kubernetes 1.4 及以上版本默认启用。 Owner 和 Dependent 一些 Kubernetes 对象是其它一些的 Owner。例如,一个 ReplicaSet 是一组 Pod 的 Owner。具有 Owner 的对象被称为是 Owner

  • 本文向大家介绍Java垃圾收集,包括了Java垃圾收集的使用技巧和注意事项,需要的朋友参考一下 示例 C ++方法-新增和删除 在像C ++这样的语言中,应用程序负责管理动态分配的内存所使用的内存。当使用new运算符在C ++堆中创建对象时,需要相应地使用delete运算符来处置该对象: 如果程序忘记了delete一个对象而只是“忘记”了该对象,则关联的内存将丢失给应用程序。这种情况的术语是内存泄

  • JavaScript 具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。 而在C 和C++之类的语言中,开发人员的一项基本任务就是手工跟踪内存的使用情况,这是造成许多问题的一个根源。在编写JavaScript 程序时,开发人员不用再关心内存使用问题,所需内存的分配以及无用内存的回收完全实现了自动管理。这种垃圾收集机制的原理其实很简单:找出那些不再继续使用的变量,然后释放其

  • 问题内容: 简短形式:CMS垃圾收集器似乎无法收集数量不断增加的垃圾;最终,我们的JVM填满,应用程序变得无响应。通过外部工具(JConsole或)强制GC 清理一次。 更新:该问题似乎与JConsole的JTop插件有关。如果我们不运行JConsole,或者在没有JTop插件的情况下运行它,则该行为消失。 (技术说明:我们正在Linux 2.6.9机器上运行32位Sun JDK 1.6.0_07

  • 问题内容: 谁能解释垃圾收集 隔离岛 的概念吗? 问题答案: 对象A引用对象B。对象B引用对象A。任何其他对象都没有引用对象A和对象B。那是一个孤立的孤岛。 基本上,隔离孤岛是一组相互引用的对象,但是应用程序中的任何活动对象都不会引用它们。严格来说,即使是单个未引用的对象也都是孤立的孤岛。 编辑评论:

  • 问题内容: 我想触发许多一次性异步CompletableFutures,例如: 理想情况下,可以在完成后将这些CompletableFutures进行垃圾回收。但是,由于我没有存储参考文献,因此是否有事先收集它们的风险? 问题答案: 您不是在显式地存储引用,而是在内部。该方法创建一个,然后向其提交引用的任务(如果您使用的是公共池)。在返回的变成了依赖于第一,因此也被引用。 一旦完成的执行,将第一个