I traced through some code. It looks like ActiveMQSession.send() does honor copyMessageOnSend as noted. But this only explains why you see 2001, not 2002 messages. Message consumption on a topic happens in a two step process: 1) During dispatch, a MessageDispatch object is enqueued to consumer's unconsumedMessage MessageDispatchChannel, then 2) During receive, the MessageDispatch is dequeued from unconsumedMessage
The message is dispatched via a call to ActiveMQMessageConsumer.dispatch(MessageDispatch md). If the consumer has a MessageListener, a copy of the message is sent to it after calls to createActiveMQMessage(md) and listener.onMessage(message). Then the original is enqueued to unconsumedMessage. I don't think you actually have such a listener, so there's a 3rd copy out there that you are missing out on :-) The copy happens on the first line of createActiveMQMessage: private ActiveMQMessage createActiveMQMessage(final MessageDispatch md) throws JMSException { ActiveMQMessage m = (ActiveMQMessage)md.getMessage().copy(); [... stuff omitted] return m; } The dispatch call happens after a long sequence of dispatch calls that go all the way back to the ActiveMQConnection object. It's onCommand() method uses a visitor pattern and the CommandVisitorAdapter it uses has this code... public Response processMessageDispatch(MessageDispatch md) throws Exception { ActiveMQDispatcher dispatcher = dispatchers.get(md.getConsumerId()); if (dispatcher != null) { // Copy in case a embedded broker is dispatching via // vm:// // md.getMessage() == null to signal end of queue // browse. Message msg = md.getMessage(); if (msg != null) { msg = msg.copy(); msg.setReadOnlyBody(true); msg.setReadOnlyProperties(true); msg.setRedeliveryCounter(md.getRedeliveryCounter()); msg.setConnection(ActiveMQConnection.this); md.setMessage(msg); } dispatcher.dispatch(md); } return null; } According to the comment, this copy is a feature of vm:// transport not a bug :-) The other copy is easier to find. When the message is consumed we instead get a call to ActiveMQMessageConsumer.receive(), which dequeues a MessageDispatch md from the MessageDispatchChannel unconsumedMessages then and calls createActiveMQMessage(md), which as we saw above makes a copy. So 1 copy on dispatch, 1 copy on receive, and a 3rd copy onMessage() if the consumer has a listener. I have no insight into the motivations here, I just eyeballed the code and described the relevant parts. Some good news: message.copy() is a shallow copy: the content (and everything else) within the message is copied by reference. See org.apache.activemq.command.Message.copy(Message copy) . -- View this message in context: http://www.nabble.com/VM-transport-not-using-pass-by-reference-tp17442075s2354p17662490.html Sent from the ActiveMQ - User mailing list archive at Nabble.com.