Memory leak in TSocket communciation with pyROOT

Hi,
I’m working on a DAQ system for my collaboration. In particular, what I’m trying to right now is to use a C++ program that spies on the data stream and fills the TH1F histograms, and opens a TServerSocket to communicate, so the histograms can be retrieved.

To retrieve the histogram, I use a simple pyROOT based class:

import time
import ROOT

import time

ROOT.gROOT.SetBatch(True)

class ROOTClient:
    def __init__(self, host='localhost', port=6060):
        self.host = host
        self.port = port
        self.socket = None
        self.histograms = []
        self.waves = []

    def connect(self):
        self.socket = ROOT.TSocket(self.host, self.port)
        if not self.socket.IsValid():
            raise ConnectionError(f"Error connecting to {self.host}:{self.port}")

    def disconnect(self):
        self.socket.Close()

    def send(self, msg):
        if self.socket.Send(msg) <= 0:
            return False
        return

    def receive(self):
        msg = ROOT.TMessage()

        if self.socket.Recv(msg) <= 0:
            return False
        
        if msg.GetClass().GetName() in ["TH1F"]:
            obj = msg.ReadObject(msg.GetClass())
            return obj
        
        return False
    
    def clear_arrays(self):
        if( len(self.histograms) == 0 ): return
        for obj in self.histograms:
            print(f"Deleting {obj.GetName()}")
            obj.Delete()
            del obj
        self.histograms = []
        if( len(self.waves) == 0 ): return
        for obj in self.waves:
            print(f"Deleting {obj.GetName()}")
            obj.Delete()
            del obj
        self.waves = []
    
    def collect(self):
        self.connect()
        self.send("get")
        self.clear_arrays()
        while True:
            obj = self.receive()
            if( obj == False ): break
            print( "Received object", obj.GetName() )
            if "Wave" in obj.GetName():
                self.waves.append(obj)
            else:
                self.histograms.append(obj)
        self.disconnect()

    def stop(self):
        self.connect()
        self.send("stop")

The histograms are retrieved from the TSocket each second by calling the collect(self) function. Everything works fine, but it seems there is a memory leak present somewhere. After about 2 hours of acquisition, the program crashes due to insufficient memory (more than 16GB is used at this point).

I tried to debug the code with the memory_profiler library, and it seems that the memory from the objects I get from the TSocket is never freed, but it increases at each collect(self) call. One of the attempts was to implement the clear_arrays(self) function, but the memory seems not to be freed anyway.

Is there something I’m overlooking, or some mistake I’m doing? I really tried everything, but it seems that there is nothing that works and each time the object is received, it is never removed.

Thank you for your help,
Jakub

_ROOT Version: 6.32/02
_Platform: Linux

Hello @skowroik,

thanks for bringing this issue to our attention!
I am not sure whether there actually is a memory leak or not in your case. I add in the loop @pcanal as he might have a better understanding of your situation.

Cheers,
Monica

There is no obvious leak in the code.

the objects I get from the TSocket is never freed,

From my reading of your code, they should be freed from:

        for obj in self.histograms:
            print(f"Deleting {obj.GetName()}")
            obj.Delete()
            del obj

are those lines executed? (also only of the 2 delete should be needed). @vpadulan any other ideas?

Yes, these lines are executed at each loop. In the meantime, I’ve managed to overcome the problem by modifying

if msg.GetClass().GetName() in ["TH1F"]:
            obj = msg.ReadObject(msg.GetClass())
            return obj

in

if msg.GetClass().GetName() in ["TH1F"]:
            obj = msg.ReadObject(msg.GetClass())
            msg.Delete()
            return obj

For some reason, TMessage is never freed? Might there be an another workaround for this? It does not seem right that at each loop I have to explicitly delete all the objects to free the memory. Could it be something with the ownership of the objects when they are send through the TSocket?

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.