golang 切片中的内存泄漏 [英] Memory leak in golang slice

查看:28
本文介绍了golang 切片中的内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚开始学习围棋,在学习切片技巧时,有几点非常令人困惑.谁能帮我澄清一下.

I just started learning go, while going through slice tricks, couple of points are very confusing. can any one help me to clarify.

在给定的切片中切割元素

To cut elements in slice its given

方法一:

a = append(a[:i], a[j:]...)

但有一个注意事项,如果使用指针可能会导致内存泄漏,推荐的方法是

but there is a note given that it may cause to memory leaks if pointers are used and recommended way is

方法二:

copy(a[i:], a[j:])
for k, n := len(a)-j+i, len(a); k < n; k++ {
    a[k] = nil // or the zero value of T
}
a = a[:len(a)-j+i]

谁能帮助我了解内存泄漏是如何发生的.我知道子切片将由主数组支持.我的想法与指针无关,我们必须始终遵循方法 2.

Can any one help me understand how memory leaks happen. I understood sub slice will be backed by the main array. My thought is irrespective of pointer or not we have to follow approach 2 always.

@icza 和 @Volker 回答后更新..

假设你有一个结构

type Books struct {
    title   string
    author  string
}

var Book1 Books
var Book2 Books 

    /* book 1 specification */
    Book1.title = "Go Programming"
    Book1.author = "Mahesh Kumar"

    Book2.title = "Go Programming"
    Book2.author = "Mahesh Kumar"

    var bkSlice = []Books{Book1, Book2}
    var bkprtSlice = []*Books{&Book1, &Book2}

现在做

bkSlice = bkSlice[:1]

bkSlice 仍然将 Book2 保存在支持数组中,该支持数组仍在内存中,并且不需要.我们需要这样做吗

bkSlice still holds the Book2 in backing array which is still in memory and is not required to be. so do we need to do

bkSlice[1] = Books{}

这样它就会被 GCed.我知道指针必须是 nil-ed,因为切片将包含对支持数组之外的对象的不必要引用.

so that it will be GCed. I understood pointers have to be nil-ed as the slice will hold unnecessary references to the objects outside backing array.

推荐答案

最简单的可以用一个简单的切片表达式来演示.

Simplest can be demonstrated by a simple slice expression.

让我们从一片 *int 指针开始:

Let's start with a slice of *int pointers:

s := []*int{new(int), new(int)}

这个切片有一个长度为 2 的后备数组,它包含 2 个非 nil 指针,指向分配的整数(后备数组之外).

This slice has a backing array with a length of 2, and it contains 2 non-nil pointers, pointing to allocated integers (outside of the backing array).

现在如果我们重新切片这个切片:

Now if we reslice this slice:

s = s[:1]

长度将变为 1.后备数组(包含 2 个指针)没有被触及,它仍然包含 2 个有效指针.即使我们现在不使用第二个指针,因为它在内存中(它是支持数组),指向的对象(这是一个用于存储 int 值的内存空间)不能被释放由垃圾收集器.

Length will become 1. The backing array (holding 2 pointers) is not touched, it sill holds 2 valid pointers. Even though we don't use the 2nd pointer now, since it is in memory (it is the backing array), the pointed object (which is a memory space for storing an int value) cannot be freed by the garbage collector.

如果你从中间剪切"多个元素,也会发生同样的事情.如果原始切片(及其支持数组)填充了非 nil 指针,并且如果您不将它们归零(使用 nil),它们将保留在记忆.

The same thing happens if you "cut" multiple elements from the middle. If the original slice (and its backing array) was filled with non-nil pointers, and if you don't zero them (with nil), they will be kept in memory.

为什么这不是非指针的问题?

实际上,这是所有指针和标题"类型(如切片和字符串)的问题,而不仅仅是指针.

Actually, this is an issue with all pointer and "header" types (like slices and strings), not just pointers.

如果你有一个 []int 类型的切片而不是 []*int,那么切片它只会隐藏"属于 的元素int 类型,无论是否存在包含它的切片,它都必须作为后备数组的一部分保留在内存中.元素不是对存储在数组外的对象的引用,而指针是指在数组外的对象.

If you would have a slice of type []int instead of []*int, then slicing it will just "hide" elements that are of int type which must stay in memory as part of the backing array regardless of if there's a slice that contains it or not. The elements are not references to objects stored outside of the array, while pointers refer to objects being outside of the array.

如果切片包含指针并且您在切片操作之前对它们nil,如果没有其他对指向对象的引用(如果数组是唯一持有指针的对象),它们可以是释放后,由于仍有切片(因此还有后备数组),它们将不会被保留.

If the slice contains pointers and you nil them before the slicing operation, if there are no other references to the pointed objects (if the array was the only one holding the pointers), they can be freed, they will not be kept due to still having a slice (and thus the backing array).

更新:

当你有一片结构时:

var bkSlice = []Books{Book1, Book2}

如果你像这样切片:

bkSlice = bkSlice[:1]

Book2 将无法通过 bkSlice 访问,但仍会在内存中(作为支持数组的一部分).

Book2 will become unreachabe via bkSlice, but still will be in memory (as part of the backing array).

您不能 nil 它,因为 nil 不是结构的有效值.但是,您可以像这样将其 零值 分配给它:

You can't nil it because nil is not a valid value for structs. You can however assign its zero value to it like this:

bkSlice[1] = Book{}
bkSlice = bkSlice[:1]

注意 Books 结构体的值仍然在内存中,作为后备数组的第二个元素,但该结构体将是零值,因此不会保存字符串引用,因此原书作者和标题字符串可以被垃圾收集(如果没有其他人引用它们;更准确地说是从字符串标题引用的字节片).

Note that a Books struct value will still be in memory, being the second element of the backing array, but that struct will be a zero value, and thus will not hold string references, thus the original book author and title strings can be garbage collected (if no one else references them; more precisely the byte slice referred from the string header).

一般规则是递归":您只需将引用位于后备数组之外的内存的元素归零.因此,如果您有一个结构切片,只有例如int 字段,你不需要将它归零,实际上它只是不必要的额外工作.如果结构具有指针或切片的字段,或者例如其他具有指针或切片等的结构类型,则应将其归零以删除对后备数组外部内存的引用.

The general rule is "recursive": You only need to zero elements that refer to memory located outside of the backing array. So if you have a slice of structs that only have e.g. int fields, you do not need to zero it, in fact it's just unnecessary extra work. If the struct has fields that are pointers, or slices, or e.g. other struct type that have pointers or slices etc., then you should zero it in order to remove the reference to the memory outside of the backing array.

这篇关于golang 切片中的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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