Hi Andrew, I think I found the leak. Consider how XrdSsiTaskReal objects are managed. They are allocated here: XrdSsiSessReal.cc:260 else {if (!alocLeft || !(tP = new XrdSsiTaskReal(this, nextTID))) and released through RelTask in two places(???): // from RequestFinished() XrdSsiSessReal.cc:116 if (rtP->Kill()) RelTask(rtP); // As a result of an error in ProcessRequest() XrdSsiSessReal.cc:294 RelTask(tP); // As a result of Recycle() XrdSsiSessRea.cc:324 RelTask(tP); I think we are primarily concerned with the RelTask as a result of RequestFinished(), which happens for every Finished() call, as long as theSession is non-null. I can verify that for every ProcessRequest() that I call, there is a Finished() call. The problem is that if stopping is false, RelTask does not delete the task (stored as tP): ---- void XrdSsiSessReal::RelTask(XrdSsiTaskReal *tP) // myMutex locked! { // Delete this task or place it on the free list // DBG("RelTask dodel="<<stopping<<" id="<<tP->ID()); if (stopping) delete tP; else {tP->attList.next = freeTask; freeTask = tP; } } ---- I can verify that stopping is false on every call because I have messages that say: "RelTask dodel=0 id=0". My guess is that deletion is deferred until stopping is true, which only happens on Unprovision(). When Unprovision is called, it calls Detach() on each element in the (ad-hoc?) linked list chain of tP->attList.next . But XrdSsiTaskReal::Detach() doesn't seem to do anything but set tStat to isDead, which only seems to matter if XrdSsiTaskReal::HandleResponse() is called, and I don't see why it would get called, because no more responses should get triggered for this particular session, because we are in an XrdSsiSessReal::Unprovision call. Does this sound plausible? I'm trying to infer what I can from the code, but I think you meant for this deferred-deletion mechanism to be something clients should never worry about--I didn't find any design notes for it. -Daniel On 05/08/2014 10:15 PM, Andrew Hanushevsky wrote: > Hi Daniel, > > I can't see anything wrong. So, you should put in the old print statements > where you allocate and delete (also indicate how much you allocated). Then > we can see if you are indeed doing what you think you are doing. I can do > that as well if you give me the stuff that compiles and create the > appropriate shared library. > > Andy > > On Thu, 8 May 2014, Daniel L. Wang wrote: > >> Hi Andy, >> >> I'm trying to make sure that I don't leak memory using the client interface, >> but I still end up leaking about 100 bytes for each sequence of >> getservice-provision-request-close-cleanup. I seem to be failing to release >> memory in 2 places. Here's a valgrind report for 30 iterations of the >> sequence. >> >> ==13424== 450 bytes in 30 blocks are definitely lost in loss record 7 of 8 >> ==13424== at 0x4A07152: operator new[](unsigned long) >> (vg_replace_malloc.c:363) >> ==13424== by 0x401C92: (anonymous >> namespace)::MyRequest::MyRequest(XrdSsiSession*) (myclient.cc:30) >> ==13424== by 0x402693: (anonymous namespace)::MyResource::makeRequest() >> (myclient.cc:177) >> ==13424== by 0x40263F: (anonymous >> namespace)::MyResource::ProvisionDone(XrdSsiSession*) (myclient.cc:171) >> ==13424== by 0x4C279C9: >> XrdSsiSessReal::HandleResponse(XrdCl::XRootDStatus*, XrdCl::AnyObject*) >> (XrdSsiSessReal.cc:157) >> ==13424== by 0x4C26C69: >> XrdCl::ResponseHandler::HandleResponseWithHosts(XrdCl::XRootDStatus*, >> XrdCl::AnyObject*, std::vector<XrdCl::HostInfo, >> std::allocator<XrdCl::HostInfo> >*) (XrdClXRootDResponses.hh:850) >> ==13424== by 0x4F47693: (anonymous >> namespace)::OpenHandler::HandleResponseWithHosts(XrdCl::XRootDStatus*, >> XrdCl::AnyObject*, std::vector<XrdCl::HostInfo, >> std::allocator<XrdCl::HostInfo> >*) (XrdClFileStateHandler.cc:86) >> ==13424== by 0x4F3AEDF: XrdCl::XRootDMsgHandler::HandleResponse() >> (XrdClXRootDMsgHandler.cc:1008) >> ==13424== by 0x4F38204: XrdCl::XRootDMsgHandler::Process(XrdCl::Message*) >> (XrdClXRootDMsgHandler.cc:300) >> ==13424== by 0x4F198D1: XrdCl::Stream::HandleIncMsgJob::Run(void*) >> (XrdClStream.hh:279) >> ==13424== by 0x4F6FFED: XrdCl::JobManager::RunJobs() >> (XrdClJobManager.cc:148) >> ==13424== by 0x4F6FB37: RunRunnerThread (XrdClJobManager.cc:33) >> ==13424== >> ==13424== 3,360 bytes in 30 blocks are definitely lost in loss record 8 of 8 >> ==13424== at 0x4A075BC: operator new(unsigned long) >> (vg_replace_malloc.c:298) >> ==13424== by 0x4C27F8C: XrdSsiSessReal::ProcessRequest(XrdSsiRequest*, >> unsigned short) (XrdSsiSessReal.cc:260) >> ==13424== by 0x4026DC: (anonymous namespace)::MyResource::makeRequest() >> (myclient.cc:179) >> ==13424== by 0x40263F: (anonymous >> namespace)::MyResource::ProvisionDone(XrdSsiSession*) (myclient.cc:171) >> ==13424== by 0x4C279C9: >> XrdSsiSessReal::HandleResponse(XrdCl::XRootDStatus*, XrdCl::AnyObject*) >> (XrdSsiSessReal.cc:157) >> ==13424== by 0x4C26C69: >> XrdCl::ResponseHandler::HandleResponseWithHosts(XrdCl::XRootDStatus*, >> XrdCl::AnyObject*, std::vector<XrdCl::HostInfo, >> std::allocator<XrdCl::HostInfo> >*) (XrdClXRootDResponses.hh:850) >> ==13424== by 0x4F47693: (anonymous >> namespace)::OpenHandler::HandleResponseWithHosts(XrdCl::XRootDStatus*, >> XrdCl::AnyObject*, std::vector<XrdCl::HostInfo, >> std::allocator<XrdCl::HostInfo> >*) (XrdClFileStateHandler.cc:86) >> ==13424== by 0x4F3AEDF: XrdCl::XRootDMsgHandler::HandleResponse() >> (XrdClXRootDMsgHandler.cc:1008) >> ==13424== by 0x4F38204: XrdCl::XRootDMsgHandler::Process(XrdCl::Message*) >> (XrdClXRootDMsgHandler.cc:300) >> ==13424== by 0x4F198D1: XrdCl::Stream::HandleIncMsgJob::Run(void*) >> (XrdClStream.hh:279) >> ==13424== by 0x4F6FFED: XrdCl::JobManager::RunJobs() >> (XrdClJobManager.cc:148) >> ==13424== by 0x4F6FB37: RunRunnerThread (XrdClJobManager.cc:33) >> >> Is there something that sticks out at you? Code attached. >> >> Thanks, >> -Daniel >> >> ######################################################################## Use REPLY-ALL to reply to list To unsubscribe from the QSERV-L list, click the following link: https://listserv.slac.stanford.edu/cgi-bin/wa?SUBED1=QSERV-L&A=1