Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re^2: IPC::Shareable sometimes leaks memory segments

by stevieb (Canon)
on Jul 08, 2019 at 23:06 UTC ( #11102574=note: print w/replies, xml ) Need Help??


in reply to Re: IPC::Shareable sometimes leaks memory segments
in thread IPC::Shareable sometimes leaks memory segments

That does work correctly in this case, thanks!

I had tried that previously in my project, but I didn't have much consistency in how I was doing things at the time (so I'm unsure if that's the reason it wasn't working). I'll apply this to the real code after I get it aligned properly, and report back.

The issue there if I remember correctly, is I've got external processes using the same shared memory, so destroy wouldn't take until the external procs exited as well. Again, I'll try it again after I get things cleaned up. It's very likely I was holding things open by accident before.

Replies are listed 'Best First'.
Re^3: IPC::Shareable sometimes leaks memory segments
by bliako (Vicar) on Jul 09, 2019 at 10:05 UTC
    clean_up_all : This is a class method that provokes IPC::Shareable to remove all shared memory segments encountered by the process. Segments are removed even if they were not created by the calling process.
    
    Calling remove() on the object underlying a tie()d variable removes the associated shared memory segment. The segment is removed irrespective of whether it has the destroy option set or not and irrespective of whether the calling process created the segment.
     specifying the destroy option when tie()ing a variable coerces IPC::Shareable to remove the underlying shared memory segment when the process calling tie() exits gracefully. Note that any related shared memory segments created automagically by the use of references will also be removed.

    But this does nothing for me:

    $tied = tie %hash, 'IPC::Shareable', { key => 'test', # destroy => 'yes', create => 1 }; IPC::Shareable->clean_up_all; # but this does: # $tied->remove; exit 0;

    so I am confused.

      I've been pouring over the code in the distribution over the last day, and am putting together the code paths quite nicely, and I've learned a LOT about the shared memory subsystem in general. Also, I've never delved into tie'd variables before, so I went down that rabbit hole so I understood what's going on there.

      I've copied the code into a new repository, and will get this sorted out for sure (as to why cleanup isn't working properly especially). Now that I know how the overall thing hangs together, I now know what part of my problem was...

      In the case that was causing me the most grief, was having two separate processes running (ie. completely unrelated, two separate scripts/process stacks). When the first one went out of scope, it would remove all segments (and semaphores), thereby destroying the shared data in the process. When the other, still running proc next attempted to access the shared data, it would die because the underlying memory was gone.

      That's why I couldn't use destroy, but because the cleanup routines don't reliably work, I was left with leaks.

      So, I'm currently trying to figure out a) why the cleanup routines don't work in all cases and how to fix it, and b) the most logical way to ensure at least one segment stays alive until *all* processes (unrelated or not) go out of scope.

      Because I'm still figuring it all out, I'm unsure how to do that yet, but one attempt will be trying to add a reference to the tied variable within the shared memory itself, and then pulling it in from there into each separate object that accesses it. Whether that's a valid approach, I'm unsure at this time.

      There are quite a few things within the code already I see I'm going to want to modify/remove/add, but everything completely hinges on me getting the clean routines working precisely. I'm even weighing the possibility of ditching the tied var entirely, and going more along the lines of IPC::ShareLite, and adding in my own serialization routine. That's thinking too far ahead yet though; I still need more knowledge on the "keeping the data shared, while keeping the memory segments/semaphores in check" stuff.

      I'll definitely be writing a blog post about this entire learning process once I've got an exceptionally good grasp of things. This isn't something I thought I'd get so distracted by, but I've found that it's a very interesting topic, and I can already see future uses for some of my projects (even stuff that the Shareable modules don't yet currently do).

      Problem 2 (problem that spawned this whole venture):

      ...if the initiating process goes out of scope/exits before a second process exits (ie. not forked, but a separate script in a different window), the entire shared memory goes away with the originating stack, leaving the remaining running separate process with no access to the shared data (crash).

      Fix:

      This is exceptionally tentative, and is currently just a test to ensure my thinking works. Add new example method leave_one() to IPC::Shareable, that acts exactly as clean_up(), but stops removing the underlying memory segments as soon as a single one is left. I also hacked the END block to do the same (END does the same thing as clean_up()).

      For my test, I created a 2main.pl, which I introduce a sleep before calling B::run(). I start main.pl in a normal clean run, then immediately start 2main.pl. When main.pl's stack goes out of scope, 2main.pl resumes operation. Everything works, the data structure (and underlying memory segment) are still available.

      Before, the clean up routines would remove ALL segments, destroying the data with it, which rendered 2main.pl to crash horribly.

      At first I was trying to share the tied variable with other processes (as I thought a refcnt would work here), but that failed.

      So now, I'll drum up something so that the variable in shared memory has at minimum the semaphore and memory segment IDs of whatever one is not cleaned up, and in my own software, write a routine that says "if there are no more of our objects in any proc whatsoever registered in the shared variable, blow away the last mem segment.

      That's far more than hypothetical, but obviously the details will change as I move forward.

      This'll likely be my last post on the topic now that I have the two core problems resolved, unless I find something else significantly interesting. Once I get the software re-written to be more adaptable and get my software working flawlessly, I'll do a big writeup :)

      Getting a bit somewhere. Problem 1:

      If script dies in main, mem segment leaked... going through the code, there's a %Global_Reg class hash which stashes all shmem and semaphore information. HOWEVER, the segment/semaphores don't get written into this hash until a write operation is performed on the shared variable. So in my main.pl die() test, I was dying before a single write, hence, the %Global_Reg hash isn't populated with the segment ID, and therefore isn't cleaned up in the clean routines.

      Fix? For now, in B.pm, I've:

      our %hash; $hash{B} = 1;

      B.pm simply writes something to the shared hash immediately after its declared, thereby creating the necessary entry in %Global_Reg, ready for cleanup.

      Currently, I'm just adding debugging info into the Shareable modules to pinpoint what's happening (and supposed to be happening) when. I'm not making any functional changes until I fully understand the processes. Once I'm confident in how things all hang together, I'll go over my notes and make the relevant changes to improve the functionality of the distribution (well, at least for my needs).

      At minimum so far, I'll eventually re-write error handling, internal information management, write methods in order to access much more of the internal information (for example, pull an actual shared mem segment object if a user wants to manually blow one away), and specifically, improve the documentation greatly.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://11102574]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (4)
As of 2019-11-12 01:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Strict and warnings: which comes first?



    Results (64 votes). Check out past polls.

    Notices?