Skip to content

goroutine leak at cache.go:1079 - runJanitor #166

Open

Description

@tigerinus
package main

import (
	"testing"
	"time"

	"github.com/patrickmn/go-cache"
	"go.uber.org/goleak"
)

func leaktest(t *testing.T) {
	defer goleak.VerifyNone(t)
	cache.New(5*time.Minute, 10*time.Minute)
}

func main() {
	testSuite := []testing.InternalTest{{Name: "leaktest", F: leaktest}}
	testing.Main(func(a, b string) (bool, error) { return a == b, nil }, testSuite, nil, nil)
}

Run above code (https://go.dev/play/p/PxN4Q4-F2rG)

Result:

        [Goroutine 6 in state select, with github.com/patrickmn/go-cache.(*janitor).Run on top of the stack:
        goroutine 6 [select]:
        github.com/patrickmn/go-cache.(*janitor).Run(0xc0002f16d0, 0x0?)
        	/home/wxh/go/pkg/mod/github.com/patrickmn/go-cache@v2.1.0+incompatible/cache.go:1079 +0x85
        created by github.com/patrickmn/go-cache.runJanitor
        	/home/wxh/go/pkg/mod/github.com/patrickmn/go-cache@v2.1.0+incompatible/cache.go:1099 +0xed
        ]

It looks like https://github.com/patrickmn/go-cache/blob/v2.1.0/cache.go#L1076-L1087 does not handle exit condition properly.

Activity

  1. vithnilica commented on Apr 3, 2023

    @vithnilica

    it's work

    import (
    	"runtime"
    	"testing"
    	"time"
    
    	"github.com/patrickmn/go-cache"
    	"go.uber.org/goleak"
    )
    
    func leaktest(t *testing.T) {
    	defer goleak.VerifyNone(t)
    	cache.New(5*time.Minute, 10*time.Minute)
    	runtime.GC()
    }
    
    func main() {
    	testSuite := []testing.InternalTest{{Name: "leaktest", F: leaktest}}
    	testing.Main(func(a, b string) (bool, error) { return a == b, nil }, testSuite, nil, nil)
    }
  2. ponder2000 commented on May 17, 2023

    @ponder2000

    I am also getting the similar kind of error as follows

    range_service  | goroutine 876 [select, 2 minutes]:
    range_service  | github.com/patrickmn/go-cache.(*janitor).Run(0xc001627fb0, 0xc0011b9140?)
    range_service  | 	/Users/jay/go/pkg/mod/github.com/patrickmn/go-cache@v2.1.0+incompatible/cache.go:1079 +0x85
    range_service  | created by github.com/patrickmn/go-cache.runJanitor
    range_service  | 	/Users/jay/go/pkg/mod/github.com/patrickmn/go-cache@v2.1.0+incompatible/cache.go:1099 +0xed
    range_service  |
    range_service  | goroutine 877 [select, 5 minutes]:
    range_service  | github.com/patrickmn/go-cache.(*janitor).Run(0xc001634050, 0x0?)
    range_service  | 	/Users/jay/go/pkg/mod/github.com/patrickmn/go-cache@v2.1.0+incompatible/cache.go:1079 +0x85
    range_service  | created by github.com/patrickmn/go-cache.runJanitor
    range_service  | 	/Users/jay/go/pkg/mod/github.com/patrickmn/go-cache@v2.1.0+incompatible/cache.go:1099 +0xed
    

    @vithnilica Can you explain how runtime.GC() is helping and when to call this function. I am really new to go and don't understand much about memory leaks and all so can you please give an example to explain it better.

    Thanks

  3. vithnilica commented on May 17, 2023

    @vithnilica

    It is not memory leaks (or goroutine leak). "go.uber.org/goleak" test does not wait for "garbage collector".

  4. ponder2000 commented on May 17, 2023

    @ponder2000

    It is not memory leaks (or goroutine leak). "go.uber.org/goleak" test does not wait for "garbage collector".

    Can you please explain why I am getting the error(cause of the error) and how will adding a routine.GC() after every cache creation helps to resolve the error.

  5. vithnilica commented on May 17, 2023

    @vithnilica

    The test counts the number of goroutines at the beginning and at the end. You need to clean up the memory (garbage collection) before terminating the test. Golang typically does this with a delay. Before releasing an object from memory, the Golang calls a finalizer that terminates the goroutine.
    Finalizer registration in code: https://github.com/patrickmn/go-cache/blob/master/cache.go#L1123
    About finalizer: https://medium.com/a-journey-with-go/go-finalizers-786df8e17687
    About garbage collection: https://tip.golang.org/doc/gc-guide

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions