Correctly patch the memory leak related to the apatsequence

This commit is contained in:
2022-09-12 15:19:46 +02:00
parent 448f5f83fa
commit f6735a634e
2 changed files with 61 additions and 21 deletions

View File

@ -11,11 +11,14 @@ import (
"runtime" "runtime"
"unsafe" "unsafe"
log "github.com/sirupsen/logrus"
"git.metabarcoding.org/lecasofts/go/obitools/pkg/obiseq" "git.metabarcoding.org/lecasofts/go/obitools/pkg/obiseq"
) )
var _MaxPatLen = int(C.MAX_PAT_LEN) var _MaxPatLen = int(C.MAX_PAT_LEN)
var _AllocatedApaSequences = 0
// var _AllocatedApaSequences = int64(0)
var _AllocatedApaPattern = 0 var _AllocatedApaPattern = 0
// ApatPattern stores a regular pattern usable by the // ApatPattern stores a regular pattern usable by the
@ -155,31 +158,45 @@ func (pattern ApatPattern) Print() {
func MakeApatSequence(sequence *obiseq.BioSequence, circular bool, recycle ...ApatSequence) (ApatSequence, error) { func MakeApatSequence(sequence *obiseq.BioSequence, circular bool, recycle ...ApatSequence) (ApatSequence, error) {
var errno C.int32_t var errno C.int32_t
var errmsg *C.char var errmsg *C.char
var p unsafe.Pointer
seqlen := sequence.Length() seqlen := sequence.Length()
p := C.malloc(C.size_t(seqlen) + 1)
if p != nil {
_AllocatedApaSequences++
}
ic := 0 ic := 0
if circular { if circular {
ic = 1 ic = 1
} }
// copy the data into the buffer, by converting it to a Go array
cBuf := (*[1 << 31]byte)(p)
copy(cBuf[:], sequence.Sequence())
cBuf[sequence.Length()] = 0
var out *C.Seq var out *C.Seq
if len(recycle) > 0 { if len(recycle) > 0 {
out = recycle[0].pointer.pointer out = recycle[0].pointer.pointer
if (int(out.seqlen) < seqlen || int(out.seqlen) > 5*seqlen) && out.cseq != nil {
C.free(unsafe.Pointer(out.cseq))
out.cseq = nil
}
} else { } else {
out = nil out = nil
} }
if out == nil || out.cseq == nil {
p = C.malloc(C.size_t(seqlen) + 1)
// if p != nil {
// // atomic.AddInt64(&_AllocatedApaSequences, 1)
// }
} else {
p = unsafe.Pointer(out.cseq)
}
if p == nil {
log.Panicln("Cannot allocate memory chunk for Cseq Apat sequecence")
}
// copy the data into the buffer, by converting it to a Go array
cBuf := (*[1 << 31]byte)(p)
copy(cBuf[:], sequence.Sequence())
cBuf[sequence.Length()] = 0
pseqc := C.new_apatseq((*C.char)(p), C.int32_t(ic), C.int32_t(seqlen), pseqc := C.new_apatseq((*C.char)(p), C.int32_t(ic), C.int32_t(seqlen),
(*C.Seq)(out), (*C.Seq)(out),
&errno, &errmsg) &errno, &errmsg)
@ -187,6 +204,10 @@ func MakeApatSequence(sequence *obiseq.BioSequence, circular bool, recycle ...Ap
if pseqc == nil { if pseqc == nil {
message := C.GoString(errmsg) message := C.GoString(errmsg)
C.free(unsafe.Pointer(errmsg)) C.free(unsafe.Pointer(errmsg))
if p != nil {
C.free(p)
// atomic.AddInt64(&_AllocatedApaSequences, -1)
}
return NilApatSequence, errors.New(message) return NilApatSequence, errors.New(message)
} }
@ -194,15 +215,18 @@ func MakeApatSequence(sequence *obiseq.BioSequence, circular bool, recycle ...Ap
// log.Printf("Make ApatSeq called on %p -> %p\n", out, pseqc) // log.Printf("Make ApatSeq called on %p -> %p\n", out, pseqc)
seq := _ApatSequence{pointer: pseqc} seq := _ApatSequence{pointer: pseqc}
runtime.SetFinalizer(&seq, func(p *_ApatSequence) { runtime.SetFinalizer(&seq, func(apat_p *_ApatSequence) {
var errno C.int32_t var errno C.int32_t
var errmsg *C.char var errmsg *C.char
// log.Printf("Finaliser called on %p\n", p.pointer) // log.Printf("Finaliser called on %p\n", apat_p.pointer)
if p != nil && p.pointer != nil { if apat_p != nil && apat_p.pointer != nil {
C.free(unsafe.Pointer(p.pointer.cseq)) if apat_p.pointer.cseq != nil {
C.delete_apatseq(p.pointer, &errno, &errmsg) C.free(unsafe.Pointer(apat_p.pointer.cseq))
_AllocatedApaSequences-- apat_p.pointer.cseq = nil
// atomic.AddInt64(&_AllocatedApaSequences, -1)
}
C.delete_apatseq(apat_p.pointer, &errno, &errmsg)
} }
}) })
@ -230,7 +254,13 @@ func (sequence ApatSequence) Free() {
// log.Printf("Free called on %p\n", sequence.pointer.pointer) // log.Printf("Free called on %p\n", sequence.pointer.pointer)
if sequence.pointer != nil && sequence.pointer.pointer != nil { if sequence.pointer != nil && sequence.pointer.pointer != nil {
C.free(unsafe.Pointer(&sequence.pointer.pointer.cseq))
if sequence.pointer.pointer.cseq != nil {
C.free(unsafe.Pointer(sequence.pointer.pointer.cseq))
sequence.pointer.pointer.cseq = nil
// atomic.AddInt64(&_AllocatedApaSequences, -1)
}
C.delete_apatseq(sequence.pointer.pointer, C.delete_apatseq(sequence.pointer.pointer,
&errno, &errmsg) &errno, &errmsg)
@ -287,6 +317,6 @@ func (pattern ApatPattern) FindAllIndex(sequence ApatSequence, limits ...int) (l
return loc return loc
} }
func AllocatedApaSequences() int { // func AllocatedApaSequences() int {
return _AllocatedApaSequences // return int(_AllocatedApaSequences)
} // }

View File

@ -291,6 +291,9 @@ func _Pcr(seq ApatSequence,
match.Recycle() match.Recycle()
annot["reverse_error"] = errj annot["reverse_error"] = errj
// log.Debugf("amplicon sequence capacity : %d", cap(amplicon.Sequence()))
results = append(results, amplicon) results = append(results, amplicon)
} }
} }
@ -364,6 +367,7 @@ func _Pcr(seq ApatSequence,
annot["reverse_error"] = erri annot["reverse_error"] = erri
results = append(results, amplicon) results = append(results, amplicon)
// log.Debugf("amplicon sequence capacity : %d", cap(amplicon.Sequence()))
} }
} }
} }
@ -397,6 +401,10 @@ func _PCRSlice(sequences obiseq.BioSequenceSlice,
if len(sequences) > 0 { if len(sequences) > 0 {
seq, _ := MakeApatSequence(sequences[0], options.Circular()) seq, _ := MakeApatSequence(sequences[0], options.Circular())
// if AllocatedApaSequences() == 0 {
// log.Panicln("Bizarre....")
// }
amplicons := _Pcr(seq, sequences[0], options) amplicons := _Pcr(seq, sequences[0], options)
if len(amplicons) > 0 { if len(amplicons) > 0 {
@ -411,6 +419,8 @@ func _PCRSlice(sequences obiseq.BioSequenceSlice,
} }
} }
// log.Println(AllocatedApaSequences())
// seq.Free() // seq.Free()
} }