Skip to content

Commit e98919e

Browse files
committed
Fix MessageHandle memory leak on send - #53
1 parent 18c12c2 commit e98919e

File tree

2 files changed

+42
-23
lines changed

2 files changed

+42
-23
lines changed

mqjms/ConsumerImpl.go

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"runtime"
1616
"strconv"
1717
"strings"
18+
"sync"
1819

1920
"github.com/ibm-messaging/mq-golang-jms20/jms20subset"
2021
ibmmq "github.com/ibm-messaging/mq-golang/v5/ibmmq"
@@ -109,24 +110,7 @@ func (consumer ConsumerImpl) receiveInternal(gmo *ibmmq.MQGMO) (jms20subset.Mess
109110
// Set a finalizer on the message handle to allow it to be deleted
110111
// when it is no longer referenced by an active object, to reduce/prevent
111112
// memory leaks.
112-
runtime.SetFinalizer(&thisMsgHandle, func(msgHandle *ibmmq.MQMessageHandle) {
113-
consumer.ctx.ctxLock.Lock()
114-
dmho := ibmmq.NewMQDMHO()
115-
err := msgHandle.DltMH(dmho)
116-
if err != nil {
117-
118-
mqret := err.(*ibmmq.MQReturn)
119-
120-
if mqret.MQRC == ibmmq.MQRC_HCONN_ERROR {
121-
// Expected if the connection is closed before the finalizer executes
122-
// (at which point it should get tidied up automatically by the connection)
123-
} else {
124-
fmt.Println("DltMH finalizer", err)
125-
}
126-
127-
}
128-
consumer.ctx.ctxLock.Unlock()
129-
})
113+
setMessageHandlerFinalizer(thisMsgHandle, consumer.ctx.ctxLock)
130114

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

185+
/*
186+
* Set a finalizer on the message handle to allow it to be deleted
187+
* when it is no longer referenced by an active object, to reduce/prevent
188+
* memory leaks.
189+
*/
190+
func setMessageHandlerFinalizer(thisMsgHandle ibmmq.MQMessageHandle, ctxLock *sync.Mutex) {
191+
192+
runtime.SetFinalizer(&thisMsgHandle, func(msgHandle *ibmmq.MQMessageHandle) {
193+
ctxLock.Lock()
194+
defer ctxLock.Unlock()
195+
196+
dmho := ibmmq.NewMQDMHO()
197+
err := msgHandle.DltMH(dmho)
198+
if err != nil {
199+
200+
mqret := err.(*ibmmq.MQReturn)
201+
202+
if mqret.MQRC == ibmmq.MQRC_HCONN_ERROR {
203+
// Expected if the connection is closed before the finalizer executes
204+
// (at which point it should get tidied up automatically by the connection)
205+
} else {
206+
fmt.Println("DltMH finalizer", err)
207+
}
208+
209+
}
210+
211+
})
212+
213+
}
214+
201215
// ReceiveStringBodyNoWait implements the IBM MQ logic necessary to receive a
202216
// message from a Destination and return its body as a string.
203217
//

mqjms/ContextImpl.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ func (ctx ContextImpl) CreateTextMessage() jms20subset.TextMessage {
183183
defer ctx.ctxLock.Unlock()
184184

185185
var bodyStr *string
186-
thisMsgHandle := createMsgHandle(ctx.qMgr)
186+
thisMsgHandle := ctx.createMsgHandle(ctx.qMgr)
187187

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

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

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

203+
// Set a finalizer on the message handle to allow it to be deleted
204+
// when it is no longer referenced by an active object, to reduce/prevent
205+
// memory leaks.
206+
setMessageHandlerFinalizer(thisMsgHandle, ctx.ctxLock)
207+
203208
if err != nil {
204209
// No easy way to pass this error back to the application without
205210
// changing the function signature, which could break existing
@@ -220,7 +225,7 @@ func (ctx ContextImpl) CreateTextMessageWithString(txt string) jms20subset.TextM
220225
ctx.ctxLock.Lock()
221226
defer ctx.ctxLock.Unlock()
222227

223-
thisMsgHandle := createMsgHandle(ctx.qMgr)
228+
thisMsgHandle := ctx.createMsgHandle(ctx.qMgr)
224229

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

243248
var thisBodyBytes *[]byte
244-
thisMsgHandle := createMsgHandle(ctx.qMgr)
249+
thisMsgHandle := ctx.createMsgHandle(ctx.qMgr)
245250

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

262-
thisMsgHandle := createMsgHandle(ctx.qMgr)
267+
thisMsgHandle := ctx.createMsgHandle(ctx.qMgr)
263268

264269
return &BytesMessageImpl{
265270
bodyBytes: &bytes,

0 commit comments

Comments
 (0)