Navigation Menu

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

Defer to call c.free cause memory leak #43363

Closed
fenngwd opened this issue Dec 24, 2020 · 2 comments
Closed

Defer to call c.free cause memory leak #43363

fenngwd opened this issue Dec 24, 2020 · 2 comments

Comments

@fenngwd
Copy link

fenngwd commented Dec 24, 2020

What version of Go are you using (go version)?

$ go version
go version go1.15.6 linux/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE="on"
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/go/pkg/mod"
GONOPROXY="git.17bdc.com"
GONOSUMDB="git.17bdc.com"
GOOS="linux"
GOPATH="/go"
GOPRIVATE="git.17bdc.com"
GOPROXY="https://goproxy.cn,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/go/src/app/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build499985783=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I'm tring to call CGO function in my program, but it seems that cause memory leaks.

func (encoder *Bays4Encoder) Encode(src []byte) (dst []byte) {
	if len(src) == 0 {
		return
	}
	s := C.CString(string(src))
	defer C.free(unsafe.Pointer(s))

	var d *C.char
	defer C.free(unsafe.Pointer(d))
	size := C.encode_to_string(encoder.enc, s, &d)

	return C.GoBytes(unsafe.Pointer(d), C.int(size))
}
func BenchmarkBays4Encoder(b *testing.B) {
	l := 24
	inputs := make([][]byte, b.N)
	for idx := range inputs {
		inputs[idx] = []byte(makeRandomString(l))
	}

	go func() {
		fmt.Println("Trigger golang runtime gc to collect golang garbage")
		for i := 0; i < 400; i++ {
			//fmt.Println("Started to gc")
			runtime.GC()
			time.Sleep(500 * time.Millisecond)
		}
	}()

	encoder := NewBays4Encoder()
	defer encoder.Delete()
	b.ResetTimer()
	//for i := 0; i < b.N; i++{
	for _, input := range inputs {
		time.Sleep(50 * time.Microsecond)
		//if input == nil {
		//	fmt.Println("shenmegui")
		//}
		//encoded := rand.Intn(len(inputs))
		_ = encoder.Encode(input)
		//encoder.Decode(encoded)
	}
	b.StopTimer()
}

What did you expect to see?

The memory of benchmark program is increasing perpetually.

defer_c_free.mov

What did you see instead?

The memory of benchmark program is kept in some low level.

@randall77
Copy link
Contributor

var d *C.char
defer C.free(unsafe.Pointer(d))

I think this is wrong. You're always deferring C.free(nil) here. The arguments to a defer are evaluated at defer time, not at execution time. You would need the defer call after the C.encode_to_string call. Or wrap the deferred function in a func() (I think, defer func() { C.free(unsafe.Pointer(d)) }()).

@fenngwd
Copy link
Author

fenngwd commented Dec 24, 2020

@randall77 I've tested by wrapping the deferred function. Memory leak is gone. Thanks for the quick reply.

@fenngwd fenngwd closed this as completed Dec 24, 2020
@golang golang locked and limited conversation to collaborators Dec 24, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants