当我从不需要停止它时,time.Tick会导致内存泄漏吗?

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

Will time.Tick cause memory leak when I never need to stop it?

问题

考虑以下代码:

go func() {
	for now := range time.Tick(time.Minute) {
		fmt.Println(now, statusUpdate())
	}
}()

我需要这个for循环永远运行,不需要停止它。这会导致内存泄漏吗?

我知道如果我需要打破这个for循环,它会导致内存泄漏。但是如果我不需要打破这个for循环呢?

文档中提到:

虽然Tick对于不需要关闭Ticker的客户端很有用,但请注意,如果没有关闭它的方法,底层的Ticker将无法被垃圾回收器回收;它会“泄漏”。

我只是想弄清楚。

英文:

Consider the following code:

go func() {
	for now := range time.Tick(time.Minute) {
		fmt.Println(now, statusUpdate())
	}
}()

I need the for loop runs forever and never need to stop it.
Will this cause memory leak or not?

I knew if I ever need to break the for loop, it will cause memory leak. But what if I don't need to break the for loop?

> The doc says
>
> While Tick is useful for clients that have no need to shut down the Ticker, be aware that without a way to shut it down the underlying Ticker cannot be recovered by the garbage collector; it "leaks".

I just want to get it right.

答案1

得分: 6

首先,让我们看一下“内存泄漏”是什么的定义,来自Wikipedia

在计算机科学中,内存泄漏是一种资源泄漏的类型,当计算机程序以一种不正确的方式管理内存分配时,不再需要的内存不会被释放。

需要注意的是,在你引用的文档中,并没有明确提到“内存泄漏”,只是提到了“泄漏”(意思是“资源泄漏”)。所涉及的资源不仅包括ticker使用的内存,还包括运行它的goroutine。因此,我将解释这个定义适用于更广泛的“资源泄漏”。

正如你引用的文档所提到的,time.Tick不能释放ticker的资源。

因此,根据这个定义,如果在程序的任何后续点上不再需要ticker,那么就发生了资源泄漏。如果在创建后的整个程序中始终需要ticker,则不会发生泄漏。

然而,在维基百科的定义中,还有这样的说明:

当对象存储在内存中但无法被运行的代码访问时,也可能发生内存泄漏。

同样,time.Tick不能释放ticker的资源。

因此,根据这个持续的定义,可以说使用time.Tick总是会导致资源泄漏。

在实际情况中,只要你在time.Tick上使用range而没有使用break,你可以合理地确保ticker将在程序的剩余部分继续使用,而不会发生“泄漏”。如果你对一个ticker是否会永远使用有任何疑问,那么请使用time.NewTicker并适当地调用Stop()

go func() {
    ticker := time.NewTicker(time.Minute)
    defer ticker.Stop()

    for now := range ticker.C {
        fmt.Println(now, statusUpdate())
        // some exception
        if (something) {
            break
        }
    }
}()
英文:

First, let's see a definition of what a "memory leak" is, from Wikipedia:
> In computer science, a memory leak is a type of resource leak that occurs when a computer program incorrectly manages memory allocations in a way that memory which is no longer needed is not released.

It's important to note that in the doc you quoted, it does not specifically mention a "memory leak", just a "leak" (meaning "resource leak"). The resources in question are not only the memory used by the ticker, but the goroutine that runs it. Because of this, I'll interpret this definition as applying to "resource leaks" more broadly.

As mentioned by the doc you quoted, time.Tick does not make it possible to release the ticker's resources.

So by this definition, if the ticker is no longer needed at any subsequent point in the program, then a resource leak has occurred. If the ticker is always needed for the remainder of the program after created, then it's not a leak.

Further in the Wikipedia definition, however, is this note:
> A memory leak may also happen when an object is stored in memory but cannot be accessed by the running code.

Again, time.Tick does not make it possible to release the ticker's resources.

So by this continued definition, you might say that the use of time.Tick is always a resource leak.

In practical terms, as long as you range over the time.Tick without breaking, you have reasonable assurance that the ticker is going to continue to be used for the remainder of the program, and there will be no "leak". If you have any doubts of if a ticker will be used forever, then use time.NewTicker and Stop() it appropriately:

go func() {
    ticker := time.NewTicker(time.Minute)
    defer ticker.Stop()

    for now := range ticker.C {
        fmt.Println(now, statusUpdate())
        // some exception
        if (something) {
            break
        }
    }
}()

huangapple
  • 本文由 发表于 2021年7月8日 00:36:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/68289916.html
匿名

发表评论

匿名网友

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

确定