3

My question is about how Perl manages the data of objects internally.

When creating objects in Perl, the new subroutine will typically return a reference to a blessed object.

Take the following code as an example:

# Create a new object
my $object = Object->new(%data1);

# Create a new object with the same variable
$object = Object->new(%data2);

From the first call to new we create an $object that references some blessed %data1

Visual representation:

The "\" symbolizes a reference.

$object ════> \{bless %data1}

This would look as follows in memory:

The "&" symbolizes an address

MEMORY:
----------------------------------
&{bless %data1} ════> bless %data1

Then with the second call to new the value of $object is changed to reference some other blessed %data2

Visual representation:

$object ══/ /══> \{bless %data1}  # The connection to %data1 is broken
   ║
   ╚═══════════> \{bless %data2}

Now memory would look like this:

MEMORY:
----------------------------------
&{bless %data1} ════> bless %data1
&{bless %data2} ════> bless %data2

The problem is now that $object no longer stores the reference \{bless %data1}, the address &{bless %data1} and any data stored at this address is lost forever. There is no possible way to access the data stored at that location from the script anymore.

My question is . . . Is Perl smart enough to remove the data stored in &{bless %data1} once the reference to this data is lost forever, or will Perl keep that data in memory potentially causing a memory leak?

tjwrona1992
  • 8,614
  • 8
  • 35
  • 98

4 Answers4

8

Given

package Object {
   sub new { my $class = shift; bless({ @_ }, $class) }
}

my $object = Object->new( a => 1, b => 2 );

Before the second assignment, you have

           +============+   +==========+
$object -->[ Reference ---->[ Blessed  ]
           +============+   [ Hash     ]
                            [          ]   +==========+
                            [ a: --------->[ 1        ]
                            [          ]   +==========+
                            [          ]
                            [          ]   +==========+
                            [ b: --------->[ 2        ]
                            [          ]   +==========+
                            +==========+

(The arrows represent pointers.)

Perl uses reference counting to determine when to free variables. As part of the assignment, the reference count of the variable currently referenced by the name (the Reference) will be decremented, causing it to be freed[1]. This will drop the reference count of the hash, causing it to be freed[1]. This will drop the reference count of the values, causing them to be freed[1].


In Perl, you get memory leaks when you have cyclic references.

{
   my $parent = Node->new();
   my $child = Node->new();
   $parent->{children} = [ $child ];
   $child->{parent} = $parent;
}

Before exiting the block, you have

$parent               +----------------------------------------------------+
 |                    |                                                    |
 |   +============+   +-->+==========+                                     |
 +-->[ Reference -------->[ Blessed  ]                                     |
     +============+       [ Hash     ]                                     |
                          [          ]   +==========+                      |
                          [ children --->[ Array    ]                      |
                          [          ]   [          ]   +============+     |
                          +==========+   [ 0: --------->[ Reference ----+  |
                                         [          ]   +============+  |  |
                                         +==========+                   |  |
                                                                        |  |
$child                +-------------------------------------------------+  |
 |                    |                                                    |
 |   +============+   +-->+==========+                                     |
 +-->[ Reference -------->[ Blessed  ]                                     |
     +============+       [ Hash     ]                                     |
                          [          ]   +============+                    |
                          [ parent: ---->[ Reference ----------------------+
                          [          ]   +============+
                          +==========+

After existing the block, you have

                      +----------------------------------------------------+
                      |                                                    |
                      +-->+==========+                                     |
                          [ Blessed  ]                                     |
                          [ Hash     ]                                     |
                          [          ]   +==========+                      |
                          [ children --->[ Array    ]                      |
                          [          ]   [          ]   +============+     |
                          +==========+   [ 0: --------->[ Reference ----+  |
                                         [          ]   +============+  |  |
                                         +==========+                   |  |
                                                                        |  |
                      +-------------------------------------------------+  |
                      |                                                    |
                      +-->+==========+                                     |
                          [ Blessed  ]                                     |
                          [ Hash     ]                                     |
                          [          ]   +============+                    |
                          [ parent: ---->[ Reference ----------------------+
                          [          ]   +============+
                          +==========+

The memory didn't get freed because everything is still being referenced because there's a reference cycle. Since you have no way of accessing this structure (no variable names reference anything in it), it's a memory leak.


  1. Assuming nothing else references (points to) those variables.
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • 1
    Great explanation. A good ASCII art diagram is worth a thousand words :) – ThisSuitIsBlackNot Aug 12 '15 at 20:47
  • 1
    @Borodin, You are wrong. [`bless`](http://perldoc.perl.org/functions/bless.html) "tells the thingy referenced by REF that it is now an object in the CLASSNAME package." See for yourself using `perl -MDevel::Peek -e'Dump(bless(\%hash));'` and `perl -e'bless(\%hash); (\%hash)->foo'`. The former shows the OBJECT flag and STASH field attached to the hash, not the ref. The latter shows the class of the object is known even though the reference used was created after bless was called. – ikegami Aug 13 '15 at 02:45
  • @ikegami: Yes, of course you're right. I remember I worked this out for myself years ago, but there is still so much talk of a *blessed reference* that I fell for it. It's presumably because `bless` takes a reference, and you can't `bless %hash`, but presumably that's just a convenience for `bless`'s prototype – Borodin Aug 13 '15 at 11:10
  • Interesting, that is good to know. I have reworded my question so it no longer refers to objects as "blessed references." – tjwrona1992 Aug 14 '15 at 12:27
4

You're misunderstanding the way parameter passing works. $object becomes a newly-created reference whose contents may be affected by the data passed to the constructor new, but it won't be a reference to hashes %data1 or %data2 themselves as new is given only key/value contents of those hashes

The bottom line of your question seems to be whether Perl is smart enough to deallocate objects when they are no longer used, and the answer is that it is, yes

Perl keeps a count of references to each data item, and if that ever falls to zero (i.e. there is no longer any way to reach that data) then the data is considered to be available for reuse

The only case where Perl can cause a memory leack is when a data structure contains a reference to itself. In that case the number of external references may fall to zero, but the data keeps itself from being deleted by its own reference keeping the count from falling to zero

It is also much safer to avoid package variables, and use only lexical variables declared with my. Lexical variables will be destroyed automatically as they go out of scope, and so reduce the count of any reference that they may have contained. Package variables, declared with our, will exist for ther lifetime of the process and won't trigger this safeguard

If you explain a little more about why you need this information then I am sure you will get much better answers

Borodin
  • 126,100
  • 9
  • 70
  • 144
  • I need the information because I have code that creates an object and stores it in a variable, then later if some condition is met, it uses the same variable and creates a new object. It is essentially the same situation portrayed in the question. – tjwrona1992 Aug 12 '15 at 18:16
  • 1
    @tjwrona1992: Okay, but you're in the same situation as thousands of other programmers who haven't needed to ask about this. Are you encountering a memory leak? – Borodin Aug 12 '15 at 18:17
  • The way I am using it, there are no references to itself so I think I am safe. Thanks @Borodin – tjwrona1992 Aug 12 '15 at 18:17
  • 1
    @tjwrona1992: It is also much safer to avoid package variables, and use only lexical variables declared with `my`. Lexical variables will be destroyed automatically as they go out of scope, and so reduce the count of any reference that they may have contained. Package variables, declared with `our`, will exist for ther lifetime of the process and won't trigger this safeguard – Borodin Aug 12 '15 at 18:20
  • I know, I'm not using any package variables. I was just wondering if the object would remain in memory after the reference is lost (which can happen even in a lexical context) – tjwrona1992 Aug 12 '15 at 18:21
  • @tjwrona1992: Okay, I've just trying to dump as much as I can think of that is relevant so that anyone else seeking similar information is satisfied – Borodin Aug 12 '15 at 18:23
3

Perl uses a method called reference counting - it counts how many times a variable is referenced. It keeps that data in memory until the reference count drops to zero.

In your example, the first object created will disappear automatically as soon as you reassign $object. However there's a caveat - if within your object and the new process you create a circular reference, this won't happen. You can use weaken within Scalar::Util to deal with this.

You can watch it by creating a DESTROY method, which is called when an object is 'freed'.

Sobrique
  • 52,974
  • 7
  • 60
  • 101
  • Good to know. I will keep Scalar::Util in mind if I ever have a similar situation where there are circular references. – tjwrona1992 Aug 12 '15 at 18:19
0

There's reference counting garbage collection. I'm not seeing anything in your code that would trip up said. Even if there were, there's weaken in Scalar::Util, among other options.

thrig
  • 676
  • 4
  • 11
  • Could you elaborate? You seem to be saying that it would not be a problem, but specifically how does Perl handle memory in a way that this would not happen? – tjwrona1992 Aug 12 '15 at 18:06