in reply to Re^2: Massive Perl Memory Leak
in thread Massive Perl Memory Leak

Best guess. If you just commented out the two lines that call $$session->get_entries(...), you'd still not see the memory growth. Not that that would be surprising, as the rest of the code wouldn't be doing much of anything.

Looking at it from the other direction. Leave all the other code commented out and just call whichever of those two lines is appropriate--but do nothing with the results returned from the call--and the memory growth will return.

$session is a reference to the Net::SNMP object

Is that module thread safe? Are you reusing a single object to talk to multiple devices? Are you sharing one instance between threads?

You might be able to check whether the session object is accumulating data internally long after you have finished with it by using Devel::Size on $session after each call to get_entries()


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re^4: Massive Perl Memory Leak
by wagnerc (Sexton) on Jun 14, 2007 at 18:30 UTC
    Funny u mention the two lines. I left everything commented out *except* the first CIDR SNMP call, did nothing with the results, just let the data go nowhere, and the memory leak returned. Instead of using in the 700 meg range otherwise, it's now 1.2 GB. With that one call alone.

    Net::SNMP is pure Perl so should theoretically be thread safe. None of the objects are instantiated until we're working on a specific device. I call destroy on it at the end of its usage and even if it were left alone it should be overwritten at each loop.

    sub wreckobject { $session->close; undef $session; }
    And if my SNMP usage is fundamentally flawed u'ld think that all the other calls would blow it up far worse than the routing table lookups. I'll play around with various usages of the object, see if anything changes. The Net::SNMP module was the one thing even in the beginning I was hoping there was nothing wrong with and I did have a Murphy's Law gut feeling that the problem was in there.

      I know nothing about SNMP or Net::SNMP, but I just looked up the get_entries() method and the first thing I read is:

      This method performs repeated SNMP get-next-request or get-bulk-request ...

      I also notice that there is a [-maxrepetitions  => $max_reps,] optional argument which you aren't using. I don't know how to interpret that, but is there any possibility that you could be gathering a crap load more stuff than you are intending to?

      Also, since you are doing this on 100 device concurrently, maybe you would be better off using get_next_request() and fetching the columns 1 at a time? That said, it's not at all clear to me that doing so would reduce the memory usage. It looks like it might accumulate the data internally and retain it until the object is disposed of.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        Found out some big information. I wrote two test scripts, one polls the routing table of 1000 ip's, single threaded. The other polls the 1000 ip's as 100 threads. It does nothing except get the routing table -- it's the same polling code. The threaded version blows up on memory, the single threaded stays steady. So something about threads really hornkles Net::SNMP's nose. I contacted the author and he seems willing to look into it.

        But man, atleast now I know *where* the leak is coming from. O_O

        That just means that the module does get_next_request's to walk the logical column of the snmp table. Once the walk result is no longer a child of the argument, it stops and returns. I dumped $result6 and it's contents were exactly what I expected. I dumped it pre and post execution and it starts off undef and then gets just the routing table data I want. So no surprises there.

        I also dumped $session pre and post build and pre and post destruction. No surprises there either. It only retains data from the last snmp call and after the close method is called it doesn't contain any snmp data, just the object definition. I think I know why the routing info blows up the script though. These routing tables can get up to 620 K and if some leaked variable is hanging onto them then that will add up fast. That would also mean that all the calls are leaking, just that they contain less data.

        Sure. I ran this with about 1000 devices and the threaded one goes to 1.4GB. Nonthreaded stays rock steady about 32MB.

        ######routeleaker2.pl########

        ################routeleaker3.pl##############