gocv icon indicating copy to clipboard operation
gocv copied to clipboard

Memory leak with GoCV

Open DmytroUsenko opened this issue 1 year ago • 4 comments

Hi guys, I am stuck with the memory leak in my existing code. I spent several days finding the issue and finally decided to write a simple test code to check - maybe the issue with GoCV. After running I saw that I have a memory leak using GoCV. Even though I have closed mats I see memory consumption. Any ideas on how to fix it or maybe I do something wrong?

Steps to Reproduce

package main
import (
	"context"
	"errors"
	"fmt"
	"gocv.io/x/gocv"
	"log"
	"net/http"
	"runtime"
	"sync"
	"time"
)
func main() {
	const testURL = "http://xxx.xxx.xxx.xxx/any stream type "
	const initialSleep = 30 * time.Second
	const concurrency = 10
	const runDuration = 10 * time.Second

	println("Server started")
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()
	// runtime debug
	go func() {
		for {
			time.Sleep(5 * time.Second)
			fmt.Printf(
				"num_routines: %d, num_opened_mats: %d\n",
				runtime.NumGoroutine(),
				gocv.MatProfile.Count(),
			)
		}
	}()
	println("Initial sleep - go check memory usage before cameras started")
	time.Sleep(initialSleep)
	println("Starting cameras...")
	ctx, cancelFunc := context.WithTimeout(context.Background(), runDuration)
	defer cancelFunc()
	wg := &sync.WaitGroup{}
	for n := 0; n < concurrency; n++ {
		wg.Add(1)
		go func() {
			err := run(ctx, wg, testURL)
			if err != nil {
				println("ERROR: ", err.Error())
			}
		}()
	}
	wg.Wait()
	println("--------------")
	println("--------------")
	println("All camera routines finished, but the server is still running. You can check RAM again")

	<-make(chan bool) // do not stop the server
}

func run(ctx context.Context, wg *sync.WaitGroup, url string) error {
	defer wg.Done()
	webcam, err := gocv.VideoCaptureFile(url)
	if err != nil {
		return err
	}
	defer func() {
		if err := webcam.Close(); err != nil {
			panic("Failed to close stream: " + err.Error())
		}
	}()
	webcam.Set(gocv.VideoCaptureBufferSize, 2)

	img := gocv.NewMat()
	defer func() {
		if err := img.Close(); err != nil {
			panic("Failed to close Mat: " + err.Error())
		}
	}()
	if ok := webcam.Read(&img); !ok {
		return errors.New("failed to perform initial read")
	}
	for i := 0; ; i++ {
		if ctx.Err() != nil {
			println("time's over, quiting")
			break
		}

		if i%100 == 0 {
			fmt.Printf(".") // just show the process is alive
		}
		if ok := webcam.Read(&img); !ok {
			fmt.Sprintln("failed to read frame")
			time.Sleep(1 * time.Second)
			continue
		}
		if img.Empty() {
			panic("empty image")
		}
	}

	fmt.Println("Finished run")
	return nil
}
  1. Run the code with -tags matprofile build options
  • Operating System and version: MacOS/Linux
  • OpenCV version used: 4.6
  • How did you install OpenCV? the standard way
  • GoCV version used: latest
  • Go version: 1.19

DmytroUsenko avatar Sep 19 '22 08:09 DmytroUsenko