rabbitmq / rabbitmq-objc-client

RabbitMQ client for Objective-C and Swift
https://rabbitmq.com
Other
242 stars 84 forks source link

RMQConnection leaking memory when recreated #193

Closed BarryDuggan closed 2 years ago

BarryDuggan commented 2 years ago

RMQConnection leaking memory when recreated.

Steps to reproduce

In Xcode Set Live Allocation Logging

Repeat steps 1 - 4 a few times Select Memory Graph in Xcode to View Memory Warnings

Expected Results

1 instance of RMQConnection Will Exist

Actual Results

Multiple instances of RMQConnection Exist. Many Memory Leaks reported in Xcode.

Sample Code

import UIKit
import RMQClientNC

class ViewController: UIViewController {
    let amqp = "insert-rmq-url-here"
    fileprivate var connection: RMQConnection?
    fileprivate var channel: RMQChannel?
    fileprivate var receivingChannel: RMQChannel?
    fileprivate var consumer: RMQConsumer?
    fileprivate var queue: RMQQueue?
    fileprivate let delegateQueue = DispatchQueue(label: "rmq-test-queue")
    override func viewDidLoad() {
        super.viewDidLoad()
        startup()
    }

    @IBAction func restartConnection() {
        print("Restarting")
        self.connection?.close()
        self.connection = nil
        self.connection?.delegate = nil
        self.receivingChannel = nil
        self.channel = nil
        self.consumer = nil
        self.startup()
    }
    /// start the connection and subscribe to the exchange
    func startup() {
        weak var this = self
        if connection == nil {
            connection = RMQConnection(uri: amqp, delegate: this)
            connection?.start()
        }
    }

}

extension ViewController: RMQConnectionDelegate {
    /// @brief Called when a socket cannot be opened, or when AMQP handshaking times out for some reason.
    func connection(_ connection: RMQConnection!, failedToConnectWithError error: Error!) {
        print(self)
        print("RABBIT: failedToConnectWithError")
    }

    /// @brief Called when a connection disconnects for any reason
    func connection(_ connection: RMQConnection!, disconnectedWithError error: Error!) {
        print(self)
        print("RABBIT: disconnectedWithError")
    }

    /// @brief Called before the configured http://www.rabbitmq.com/api-guide.html#recovery automatic connection recovery</a> sleep.
    func willStartRecovery(with connection: RMQConnection!) {
        print(self)
        print("RABBIT: willStartRecovery")
    }

    /// @brief Called after the configured http://www.rabbitmq.com/api-guide.html#recovery automatic connection recovery</a> sleep.
    func startingRecovery(with connection: RMQConnection!) {
        print(self)
        print("RABBIT: startingRecovery")
    }

    /*!
     * @brief Called when http://www.rabbitmq.com/api-guide.html#recovery automatic connection recovery</a> has succeeded.
     * @param RMQConnection the connection instance that was recovered.
     */
    func recoveredConnection(_ connection: RMQConnection!) {
        print(self)
        print("RABBIT: recoveredConnection")

    }

    /// @brief Called with any channel-level AMQP exception.
    func channel(_ channel: RMQChannel!, error: Error!) {
        print(self)
        print("RABBIT: Channel Error")
    }
}
michaelklishin commented 2 years ago

@BarryDuggan I don't see any evidence of a problem in the client. It does not instantiate or keep references to RMQConnection, your own code does.

You are welcome to investigate this and provide evidence, this is open source software after all.