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

Memory leak when QoS > 1 #56

Closed
RafalGoslawski opened this issue May 2, 2013 · 4 comments

Comments

Projects
None yet
3 participants
@RafalGoslawski
Copy link

commented May 2, 2013

Hello,

When using prefetch count higher than 1, I experience memory leak.
Am I missing something or is this a bug?
The code below allocates memory and never releases it, and eventually system crashes.

#include <SimpleAmqpClient.h>
#include <iostream>

using namespace AmqpClient;
using namespace std;

int main()
{
    // queue name
    string queue = "test-queue";
    // connect
    Channel::ptr_t channel = Channel::Create("localhost",5672,"guest","guest","rafal-test",131072);
    // declare queue
    channel->DeclareQueue(queue,false,true,false,false);
    // create message
    BasicMessage::ptr_t message = BasicMessage::Create("The message.");
    // publish it couple of times so we can use some prefetch
    for (int i=0; i<10; i++)
        channel->BasicPublish("", queue, message, false, false);
    // create consumer, QoS = 10
    std::string consumer = channel->BasicConsume(queue,"ConsumerTag1",false,false,false,10);
    // keep looping
    for (int i=0; true; i++)
    {
        // delay every 1000 iterations to slow things down a bit
        if (i%1000 == 0)sleep(1);
        // consume message
        Envelope::ptr_t envelope = channel->BasicConsumeMessage(consumer);
        // show counter
        cout << i << " Received message with body: " << envelope->Message()->Body() << std::endl;
        // publish back to the queue
        channel->BasicPublish("", queue, envelope->Message(), false, false);
        // ack consumed message
        channel->BasicAck(envelope->GetDeliveryInfo());
    }
}
@alanxz

This comment has been minimized.

Copy link
Owner

commented May 2, 2013

This is definitely a bug. I can reproduce the effects on my machine with the above code.

I believe the reason behind this is the way rabbitmq-c handles memory. rabbitmq-c allocates all incoming frames in a common memory pool, and it can only recycle this pool once all of the frames that have been allocated have been dealt with. When the QoS is set to be > 1, there is always a backlog of frames, so the memory pool is never allowed to recycle, thus the unbounded memory growth. Its also possible there is a frame on another channel hanging around somewhere, which would have the same effect, though not seeing the behavior when QoS == 1 makes me think its not another frame on a different channel.

This is what alanxz/rabbitmq-c#5 is supposed to solve (for a variety of reasons I don't think I will end up merging that PR). I think in this case however, I don't think even that will help, as this is all happening in one channel.

I think the 'solution' is: internally when reading frames we need to try hard to immediately use all of the frames that rabbitmq-c generates so that the memory pool can be recycled.

@RafalGoslawski

This comment has been minimized.

Copy link
Author

commented May 2, 2013

The problem exists when there is only one channel. If I use seperate channels for consume/ack and publish memory pool is recycled just fine. But that's just a workaround not a solution.

@alanxz

This comment has been minimized.

Copy link
Owner

commented May 2, 2013

Interesting. Given what I think the problem is - I would not have expected separating out publish and consumer to their own Channel objects would've alleviated the memory issue. But I'm glad you found a workaround for the moment.

@chenyujian

This comment has been minimized.

Copy link

commented May 3, 2013

#30

@alanxz alanxz closed this in 49b8ba8 Aug 15, 2013

alanxz added a commit that referenced this issue Sep 3, 2013

Assemble messages as frames are queued
Attempt to assemble envelopes frames are added to the internal frame queue. This
will allow memory to be more readily freed, and prevent unbounded growth of
memory where QoS > 1.

This should solve issue #56 completely.

alanxz added a commit that referenced this issue Sep 3, 2013

Assemble messages as frames are queued
Attempt to assemble envelopes frames are added to the internal frame queue. This
will allow memory to be more readily freed, and prevent unbounded growth of
memory where QoS > 1.

This should solve issue #56 completely.

alanxz added a commit that referenced this issue Sep 4, 2013

Assemble messages as frames are queued
Attempt to assemble envelopes frames are added to the internal frame queue. This
will allow memory to be more readily freed, and prevent unbounded growth of
memory where QoS > 1.

This should solve issue #56 completely.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.