Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible memory leak at DMap.Scan() #263

Open
dronnix opened this issue Nov 12, 2024 · 0 comments
Open

Possible memory leak at DMap.Scan() #263

dronnix opened this issue Nov 12, 2024 · 0 comments
Assignees
Labels
bug Something isn't working

Comments

@dronnix
Copy link

dronnix commented Nov 12, 2024

Hi!

I spotted that each Scan() call leaves a couple of goroutines alive (an iterator is closed). Minimum reproducing example:

package main

import (
	"context"
	"fmt"
	"log"
	"runtime"
	"time"

	"github.com/buraksezer/olric"
	"github.com/buraksezer/olric/config"
)

func main() {
	// Sample for Olric v0.5.x

	// Deployment scenario: embedded-member
	// This creates a single-node Olric cluster. It's good enough for experimenting.

	// config.New returns a new config.Config with sane defaults. Available values for env:
	// local, lan, wan
	cfg := config.New("local")

	// Callback function. It's called when this node is ready to accept connections.
	ready := make(chan struct{}, 1)
	cfg.Started = func() {
		ready <- struct{}{}
		log.Println("[INFO] Olric is ready to accept connections")
	}
	
	// Create a new Olric instance.
	db, err := olric.New(cfg)
	if err != nil {
		log.Fatalf("Failed to create Olric instance: %v", err)
	}

	// Start the instance. It will form a single-node cluster.
	go func() {
		// Call Start at background. It's a blocker call.
		err = db.Start()
		if err != nil {
			log.Fatalf("olric.Start returned an error: %v", err)
		}
	}()

	<-ready

	// In embedded-member scenario, you can use the EmbeddedClient. It implements
	// the Client interface.
	client := db.NewEmbeddedClient()

	dm, err := client.NewDMap("bucket-of-arbitrary-items")
	if err != nil {
		log.Fatalf("olric.NewDMap returned an error: %v", err)
	}

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)

	// Create N key-value pairs:
	const N = 10
	for i := range N {
		key := fmt.Sprintf("key-%d", i)
		value := fmt.Sprintf("value-%d", i)
		if err = dm.Put(ctx, key, value); err != nil {
			log.Fatalf("DMap.Put returned an error: %v", err)
		}
	}

	// Iterate M times over N keys:
	const M = 10
	for range M {
		iter, err := dm.Scan(ctx)
		if err != nil {
			log.Fatalf("DMap.Scan returned an error: %v", err)
		}
		for iter.Next() {
			// Do nothing
		}
		iter.Close() // close the iterator explicitly
	}

	// Dispose all the allocated resources:
	if err := dm.Destroy(ctx); err != nil {
		log.Fatalf("Failed to destroy DMap: %v", err)
	}
	if err := client.Close(ctx); err != nil {
		log.Fatalf("Failed to close EmbeddedClient: %v", err)
	}
	if err := db.Shutdown(ctx); err != nil {
		log.Fatalf("Failed to shutdown Olric: %v", err)
	}

	cancel()                // cancel the context, passed to the all methods above, explicitly
	runtime.GC()            // run GC explicitly
	time.Sleep(time.Second) // wait a bit

	s := runtime.MemStats{}
	runtime.ReadMemStats(&s)
	const KB = 1 << 10
	fmt.Printf("Non-Freed objects: %d, Mem in use(KB): %d\n", s.Mallocs-s.Frees, s.HeapAlloc/KB)
	fmt.Printf("GoRoutines remained: %d\n", runtime.NumGoroutine())
}

Outputs:

Non-Freed objects: 7597, Mem in use(KB): 966
GoRoutines remained: 22

Goroutines are got stuck at:

runtime.gopark (proc.go:425) runtime
runtime.selectgo (select.go:335) runtime
olric.(*ClusterClient).fetchRoutingTablePeriodically (cluster_client.go:757) github.com/buraksezer/olric
olric.NewClusterClient.gowrap1 (cluster_client.go:836) github.com/buraksezer/olric
runtime.goexit (asm_arm64.s:1223) runtime
 - Async Stack Trace
olric.NewClusterClient (cluster_client.go:836) github.com/buraksezer/olric
@buraksezer buraksezer self-assigned this Nov 13, 2024
@buraksezer buraksezer added the bug Something isn't working label Nov 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants