在Golang中,将局部变量的指针传递给通道是安全的吗?

huangapple go评论81阅读模式
英文:

Is it safe to pass pointer of a local variable to a channel in Golang?

问题

我有一个代码块,用于查询 AD 并检索结果并写入一个通道。

func GetFromAD(connect *ldap.Conn, ADBaseDN, ADFilter string, ADAttribute []string, ADPage uint32) *[]ADElement {

    searchRequest := ldap.NewSearchRequest(ADBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, ADFilter, ADAttribute, nil)
    sr, err := connect.SearchWithPaging(searchRequest, ADPage)
    CheckForError(err)
    fmt.Println(len(sr.Entries))
    ADElements := []ADElement{} 
    for _, entry := range sr.Entries{
        NewADEntity := new(ADElement) //struct
        NewADEntity.DN = entry.DN
        for _, attrib := range entry.Attributes {
            NewADEntity.attributes = append(NewADEntity.attributes, keyvalue{attrib.Name: attrib.Values})
        }
        ADElements = append(ADElements, *NewADEntity)
    }
    return &ADElements
}

上述函数返回一个指向 []ADElements 的指针。

在我的 initialrun 函数中,我这样调用这个函数:

ADElements := GetFromAD(connectAD, ADBaseDN, ADFilter, ADAttribute, uint32(ADPage))
fmt.Println(reflect.TypeOf(ADElements))
ADElementsChan <- ADElements

输出结果为:

*[]somemodules.ADElement

我的疑问是,由于在 GetFromAD() 中定义的 ADElements := []ADElement{} 是一个局部变量,它必须在堆栈中分配,并且当 GetFromAD() 退出时,堆栈的内容必须被销毁,并且对 GetFromAD() 的进一步引用必须指向无效的内存引用,但是我仍然得到了由 GetFromAD() 返回的确切元素数量,而没有出现任何段错误。这是如何工作的?这种做法安全吗?

英文:

I have a code block that queries AD and retrive the results and write to a channel.

func GetFromAD(connect *ldap.Conn, ADBaseDN, ADFilter string, ADAttribute []string, ADPage uint32) *[]ADElement {

    searchRequest := ldap.NewSearchRequest(ADBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, ADFilter, ADAttribute, nil)
    sr, err := connect.SearchWithPaging(searchRequest, ADPage)
    CheckForError(err)
    fmt.Println(len(sr.Entries))
    ADElements := []ADElement{} 
    for _, entry := range sr.Entries{
	    NewADEntity := new(ADElement) //struct
	    NewADEntity.DN = entry.DN
	    for _, attrib := range entry.Attributes {
		    NewADEntity.attributes = append(NewADEntity.attributes, keyvalue{attrib.Name: attrib.Values})
	    }
	    ADElements = append(ADElements, *NewADEntity)
	}
    return &amp;ADElements
}

The above function returns a pointer to []ADElements.

And in my initialrun function, I call this function like

ADElements := GetFromAD(connectAD, ADBaseDN, ADFilter, ADAttribute, uint32(ADPage))
fmt.Println(reflect.TypeOf(ADElements))
ADElementsChan &lt;- ADElements

And the output says

*[]somemodules.ADElement

as the output of reflect.TypeOf.

My doubt here is,
since ADElements := []ADElement{} defined in GetFromAD() is a local variable, it must be allocated in the stack, and when GetFromAD() exits, contents of the stack must be destroyed, and further references to GetFromAD() must be pointing to invalid memory references, whereas I still am getting the exact number of elements returned by GetFromAD() without any segfault. How is this working? Is it safe to do it this way?

答案1

得分: 5

是的,它是安全的,因为Go编译器执行逃逸分析并将这些变量分配在堆上。

请查看常见问题 - 如何知道变量是在堆上还是栈上分配的?

> 存储位置确实对编写高效程序有影响。在可能的情况下,Go编译器会将函数内部局部变量分配在该函数的栈帧中。然而,如果编译器无法证明该变量在函数返回后不再被引用,那么编译器必须将该变量分配在垃圾回收的堆上,以避免悬空指针错误。此外,如果一个局部变量非常大,将其存储在堆上而不是栈上可能更合理。

英文:

Yes, it is safe because Go compiler performs escape analysis and allocates such variables on heap.

Check out FAQ - How do I know whether a variable is allocated on the heap or the stack?

> The storage location does have an effect on writing efficient programs. When possible, the Go compilers will allocate variables that are local to a function in that function's stack frame. However, if the compiler cannot prove that the variable is not referenced after the function returns, then the compiler must allocate the variable on the garbage-collected heap to avoid dangling pointer errors. Also, if a local variable is very large, it might make more sense to store it on the heap rather than the stack.

答案2

得分: 0

定义“安全”...

由于ADElements至少有一个活动引用,所以你不会释放ADElements的内存。

在这种情况下,你应该是完全安全的,因为你只传递了一次切片,然后似乎没有修改它,但在一般情况下,最好逐个元素通过chan ADElement传递它,以避免对切片(或更具体地说,切片后面的数组)进行多次非同步访问。

对于映射也是如此,如果你通过通道传递一个映射,然后继续访问它,可能会出现奇怪的问题。

英文:

Define "safe"...

You will not end up freeing the memory of ADElements, since there's at least one live reference to it.

In this case, you should be completely safe, since you're only passing the slice once and then you seem to not modify it, but in the general case it might be better to pass it element-by-element across a chan ADElement, to avoid multiple unsynchronized accesses to the slice (or, more specifically, the array backing the slice).

This also holds for maps, where you can get curious problems if you pass a map over a channel, then continue to access it.

huangapple
  • 本文由 发表于 2016年2月26日 18:24:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/35649171.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定