Skip to content

Commit

Permalink
Fix MessageHandle memory leak on send - ibm-messaging#53
Browse files Browse the repository at this point in the history
  • Loading branch information
matrober-uk committed Jan 22, 2023
1 parent 18c12c2 commit e98919e
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 23 deletions.
50 changes: 32 additions & 18 deletions mqjms/ConsumerImpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"runtime"
"strconv"
"strings"
"sync"

"github.com/ibm-messaging/mq-golang-jms20/jms20subset"
ibmmq "github.com/ibm-messaging/mq-golang/v5/ibmmq"
Expand Down Expand Up @@ -109,24 +110,7 @@ func (consumer ConsumerImpl) receiveInternal(gmo *ibmmq.MQGMO) (jms20subset.Mess
// Set a finalizer on the message handle to allow it to be deleted
// when it is no longer referenced by an active object, to reduce/prevent
// memory leaks.
runtime.SetFinalizer(&thisMsgHandle, func(msgHandle *ibmmq.MQMessageHandle) {
consumer.ctx.ctxLock.Lock()
dmho := ibmmq.NewMQDMHO()
err := msgHandle.DltMH(dmho)
if err != nil {

mqret := err.(*ibmmq.MQReturn)

if mqret.MQRC == ibmmq.MQRC_HCONN_ERROR {
// Expected if the connection is closed before the finalizer executes
// (at which point it should get tidied up automatically by the connection)
} else {
fmt.Println("DltMH finalizer", err)
}

}
consumer.ctx.ctxLock.Unlock()
})
setMessageHandlerFinalizer(thisMsgHandle, consumer.ctx.ctxLock)

// Message received successfully (without error).
// Determine on the basis of the format field what sort of message to create.
Expand Down Expand Up @@ -198,6 +182,36 @@ func (consumer ConsumerImpl) receiveInternal(gmo *ibmmq.MQGMO) (jms20subset.Mess
return msg, jmsErr
}

/*
* Set a finalizer on the message handle to allow it to be deleted
* when it is no longer referenced by an active object, to reduce/prevent
* memory leaks.
*/
func setMessageHandlerFinalizer(thisMsgHandle ibmmq.MQMessageHandle, ctxLock *sync.Mutex) {

runtime.SetFinalizer(&thisMsgHandle, func(msgHandle *ibmmq.MQMessageHandle) {
ctxLock.Lock()
defer ctxLock.Unlock()

dmho := ibmmq.NewMQDMHO()
err := msgHandle.DltMH(dmho)
if err != nil {

mqret := err.(*ibmmq.MQReturn)

if mqret.MQRC == ibmmq.MQRC_HCONN_ERROR {
// Expected if the connection is closed before the finalizer executes
// (at which point it should get tidied up automatically by the connection)
} else {
fmt.Println("DltMH finalizer", err)
}

}

})

}

// ReceiveStringBodyNoWait implements the IBM MQ logic necessary to receive a
// message from a Destination and return its body as a string.
//
Expand Down
15 changes: 10 additions & 5 deletions mqjms/ContextImpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func (ctx ContextImpl) CreateTextMessage() jms20subset.TextMessage {
defer ctx.ctxLock.Unlock()

var bodyStr *string
thisMsgHandle := createMsgHandle(ctx.qMgr)
thisMsgHandle := ctx.createMsgHandle(ctx.qMgr)

return &TextMessageImpl{
bodyStr: bodyStr,
Expand All @@ -195,11 +195,16 @@ func (ctx ContextImpl) CreateTextMessage() jms20subset.TextMessage {

// createMsgHandle creates a new message handle object that can be used to
// store and retrieve message properties.
func createMsgHandle(qMgr ibmmq.MQQueueManager) ibmmq.MQMessageHandle {
func (ctx ContextImpl) createMsgHandle(qMgr ibmmq.MQQueueManager) ibmmq.MQMessageHandle {

cmho := ibmmq.NewMQCMHO()
thisMsgHandle, err := qMgr.CrtMH(cmho)

// Set a finalizer on the message handle to allow it to be deleted
// when it is no longer referenced by an active object, to reduce/prevent
// memory leaks.
setMessageHandlerFinalizer(thisMsgHandle, ctx.ctxLock)

if err != nil {
// No easy way to pass this error back to the application without
// changing the function signature, which could break existing
Expand All @@ -220,7 +225,7 @@ func (ctx ContextImpl) CreateTextMessageWithString(txt string) jms20subset.TextM
ctx.ctxLock.Lock()
defer ctx.ctxLock.Unlock()

thisMsgHandle := createMsgHandle(ctx.qMgr)
thisMsgHandle := ctx.createMsgHandle(ctx.qMgr)

msg := &TextMessageImpl{
bodyStr: &txt,
Expand All @@ -241,7 +246,7 @@ func (ctx ContextImpl) CreateBytesMessage() jms20subset.BytesMessage {
defer ctx.ctxLock.Unlock()

var thisBodyBytes *[]byte
thisMsgHandle := createMsgHandle(ctx.qMgr)
thisMsgHandle := ctx.createMsgHandle(ctx.qMgr)

return &BytesMessageImpl{
bodyBytes: thisBodyBytes,
Expand All @@ -259,7 +264,7 @@ func (ctx ContextImpl) CreateBytesMessageWithBytes(bytes []byte) jms20subset.Byt
ctx.ctxLock.Lock()
defer ctx.ctxLock.Unlock()

thisMsgHandle := createMsgHandle(ctx.qMgr)
thisMsgHandle := ctx.createMsgHandle(ctx.qMgr)

return &BytesMessageImpl{
bodyBytes: &bytes,
Expand Down

0 comments on commit e98919e

Please sign in to comment.