• Visual Basic: Avoiding Memory Leaks in Objects


    Avoiding Memory Leaks in Objects  http://www.vbi.org/Items/article.asp?id=106
    In this article, I will discuss the potential memory leak that can occur if object references aren't handled in a proper way.

    Author: Jens G. Balchen

    Introduction

    In modern Visual Basic, objects play a vital role. Since version 4.0, VB developers have had the opportunity to create and destroy objects at their own will. To understand why objects can and will cause memory leaks in Visual Basic, you have to understand how they work.

    Creating the Object

    Whenever you create an object in Visual Basic, you actually create two things -- an object, and a pointer (called an object reference). "VB does not use pointers", you might say, but that is not true. "VB does not let you manipulate pointers" is more precise. Behind the scenes, VB still makes extensive use of pointers.

    The following code will create an object and a reference, both referred to as A:

    Dim A As Class1
    
       Set A = New Class1
    
    

    To VB, this code reads something like this:

    Create an object reference (pointer) called A to an object of type Class1
    Create a new instance of Class1 and make A point to this instance.
    
    

    If at some point you were to write

    Dim B As Class1
    
       Set B = A
    
    

    what would have happened, is

    Create an object reference (pointer) called B to an object of type Class1
    Make B point to the same object instance as A.
    
    

    If you modify B, A will have been modified as well, which is quite obvious since they refer to the same object.

    Destroying the Object

    To destroy an object in VB, you set it to Nothing. But wait a minute. If all we ever use are object pointers, how can we set the object itself to Nothing? The answer is: We can't.

    When we set a reference to Nothing, something called the garbage collector kicks in. This little piece of software tries to determine whether or not an object should be destroyed. There are many ways to implement a garbage collector, but Visual Basic uses what is called the reference count method.

    As I said earlier, all we ever use are references. When I execute the following code, I will not touch the object directly; instead, I will reset and destroy the object reference.

    Dim A As Class1
    
       Set A = New Class1
       Set A = Nothing
       
    

    When VB interprets the last line, it will remove the reference A. At this point, if the object has no more references, the garbage collector will destroy the object and deallocate all its resources. If any other references point to the same object, the object will not be destroyed.

    Dim A As Class1
    Dim B As Class1
    
       Set A = New Class1
       Set B = A
       Set A = Nothing
       
    

    At this point, the object will still be alive, since B holds a reference to it.

    Fooling the Garbage Collector

    The garbage collector is not really very smart, and it cannot keep up with the incredible pace at which humans produce errors. There is an easy way to trick the garbage collector into thinking an object should be kept alive indefinetely. This can best be illustrated with these two classes, Class1 and Class2.

    ' Class1 code
    Option Explicit
    
    Public A As Class2
    
    Public Sub Class_Initialize()
    
       Set A = New Class2
       Set A.B = Me
    
    End Sub
    
    ' Class2 code
    Option Explicit
    
    Public B As Class1
    
    

    When an instance of Class1 is created, it will create an instance of Class2. This way, Class1 keeps a reference to Class2. But it will also set a reference in Class2... to itself. This way, Class1 referes to Class2, and Class2 referes to Class1. This is what we call circular references.

    If I were to create and destroy an object of Class1, this is what I would do:

    Dim MyObject As Class1
    
       Set MyObject = New Class1
       ...
       Set MyObject = Nothing
       
    

    Behind the scenes, Class1 will have created another object, and set up a circular reference. When I destroy MyObject, I would expect the garbage collector to clean up. However, the garbage collector is left with the following situation:

    1. Object Class2 points to object Class1, so Class1 can't be destroyed even if MyObject is destroyed.
    2. Object Class1 points to object Class2, so Class2 can't be destroyed.

    Oops.

    Producing a Memory Leak

    Modifying the above classes, it is very easy to produce VB code that will leak memory like crazy. The following code can be pasted into two classes and a form.

    ' Class1 code
    Option Explicit
    
    Private A As New Class2
    Private Str As String
    Private Sub Class_Initialize()
    
       Set A.B = Me
       
       ' Allocate lots of memory
       Str = Space(1024 ^ 2)
    
    End Sub
    
    ' Class2 code
    Option Explicit
    
    Public B As Class1
    
    ' Form code
    Private Sub Command1_Click()
    
    Dim A As Class1
    
       Do
          ' Will allocate 1 MB of memory.
          Set A = New Class1
          ' Will leak 1 MB of memory.
          Set A = Nothing
          DoEvents
       Loop
    
    End Sub
    
    

    On my development machine, I have 256 MB RAM and 256 MB virtual memory. The following image is taken from Task Manager after this code had been running for a while, and then stopped.

    As you can see, the application is very efficient at leaking memory.

    Avoiding the Problem

    The obvious solution to this problem is avoiding circular references. However, this is not always a viable solution, since sometimes, circular references actually provide very useful functionality.

    The best way to prevent this problem from arising is keeping a clear mind and adopting a structured way of working with objects. The following procedure could be inserted into any class, and should be modified to fit the needs of that particular class:

    Public Sub Deallocate()
    
       ' Deallocate any object references and make sure they have a chance to
       ' deallocate theirs.
    	
       A.Deallocate
       Set A = Nothing
    
       B.Deallocate
       Set B = Nothing
    	
       ' ... etc...
    
    End Sub
    
    

    A more generic solution

    If you want to provide some help to yourself and other programmers you work with, you could create an interface for this type of functionality.

    Step 1: A template

    Considering the previous Deallocate function, one could create a class called SafeObject that would contain this function.

    ' SafeObject code
    
    Public Sub Deallocate()
    
    End Sub
    
    

    Step 2: Using the template

    Other objects could implement this interface, like this:

    ' Class1 code
    Option Explicit
    Implements SafeObject
    
    Private Sub SafeObject_Deallocate()
    
       ' Class1's special deallocation procedure.	
    
    End Sub
    
    

    Step 3: New ways of destroying

    The last step is to create a function in a module:

    ' mdlSafeObject code
    
    Public Sub DestroyObject(o As Object)
    
    Dim SafeO As SafeObject
    
       ' If this is a SafeObject, call Deallocate() first.
       If TypeOf o Is SafeObject Then 
          ' This is necessary to make VB recognise o as a SafeObject
          Set SafeO = o
          SafeO.Deallocate
       End If
    
       Set o = Nothing
    
    End Sub
    
    ' Class1 code
    
    Public B As Class2
    Public C As Class3
    
    Private Sub SafeObject_Deallocate()
    
       ' Destroy all references.
       DestroyObject B
       DestroyObject C
    
    End Sub
    
    

    If you always use the SafeObject interface, and always use DestroyObject instead of Nothing, all objects will at least have the ability to perform a safe deallocation of their references.

  • 相关阅读:
    oracle查询当天数据三种方式性能对比
    APPCAN IDE中安装emmet插件
    MAS 移动业务整合系统
    SDK 移动应用开发系统
    移动应用开发平台介绍
    安装Sublime Text 3插件的方法
    2014勿勿已过,2015已迎面而来
    入驻博客园
    zkw线段树
    贪心题
  • 原文地址:https://www.cnblogs.com/harrychinese/p/14284774.html
Copyright © 2020-2023  润新知