2

If you define a class instance in a function, when the function exits, the instance will be automatically destroyed due to out of scope. This can be simply verified by a small program:

class A(object):
    def __del__(self):
        print 'deleting A ', id(self)

class B(A):
    def __init__(self):
        self.a = A()

    def __del__(self):
        print 'deleting B ', id(self)
        super(B, self).__del__()


def test():
    b = B()
    print 'this is ', b

test()

The output is:

this is  <__main__.B object at 0x01BC6150>
deleting B  29122896
deleting A  29122896
deleting A  29122960

But I'm encountering a weird problem. When I inherit a class from novaclient, the instance will never be automatically destroyed.

from novaclient.v1_1.client import Client as NovaClient

class ViviNovaClient(NovaClient):
    def __init__(self, auth_token, url, tenant_id):
        super(ViviNovaClient, self).__init__(None, None, tenant_id, auth_url = 'http')
        self.client.management_url = url
        self.client.auth_token = auth_token
        self.client.used_keyring = True;
        LOG.info('creating <ViviNovaClient> %d' % id(self))

    def __del__(self):
        LOG.info('deleting <ViviNovaClient> %d' % id(self))


if __name__ == '__main__':
    def test():
        client = ViviNovaClient('53ef4c407fed45de915681a2d6aef1ee',                                   
          'http://135.251.237.130:8774/v2/082d8fd857f44031858827d149065d9f',
           '082d8fd857f44031858827d149065d9f')

    test()

Output is:

2013-05-24 23:08:03 32240 INFO vivi.vivimain.ViviNovaClient [-] creating <ViviNovaClient> 26684304

In this test, 'client' object is not destroyed. So I wonder what will prevent the 'client' object from auto destroying?

Zac
  • 2,180
  • 2
  • 23
  • 36
TieDad
  • 9,143
  • 5
  • 32
  • 58

1 Answers1

5

Because a lot of other objects are storing a reference to the client too, forming many reference cycles.

For example, from the source code:

class Client(object):
    def __init__(self, username, **etc):
        password = api_key
        self.project_id = project_id
        self.flavors = flavors.FlavorManager(self)
        # etc.

We see that the Client will save a FlavorManager, and the initializer of FlavorManager (which is a Manager) will save a reference to the input Client as well:

class Manager(utils.HookableMixin):
    def __init__(self, api):
        self.api = api

Until Python starts the cycle collector, these objects will not be deleted immediately. Note that adding the __del__ methods prevents the cycle collector from running.

Community
  • 1
  • 1
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • Yeah, I also found this tricky right after I posted the question. It's because self.flavors reference to self. But how to solve this problem? If no way, that means I can only create single novaclient instance in my program. – TieDad May 24 '13 at 07:49
  • 1
    @EvanLi: I don't know how this library works, but in Python you shouldn't need to care about memory management. What's wrong with just creating 2 Client instances? – kennytm May 24 '13 at 07:51
  • My program is a long-time running process. As my current programming model is to create a novaclient whenever I need one. So thousands of novaclient object might be created. I found this memory leak problem because I noticed my process's memory usage grew from 60M to 150M after one night running. – TieDad May 24 '13 at 11:40