Talking about reference counting
Objective
As a Delphi programmer, you don't have to look at this section, but if you want to learn more about COM's internal technology, or if you have good control over the object model and the reference model, I'd like you to take some time to see what's going on, and the benefits will be obvious, You are free to use some skill to solve the problem that gives you a headache. Well, go on with our exchange today;
In component technology prerequisite knowledge Two, we have introduced the interface (Interface), when we do not have in-depth implementation of the interface/efficiency/optimization issues such as further Zen, and understand that they do for our future programming is a great help, we all know, Each interface maintains a global variable frefcount (this is the name of the variable in Object Pascal, which, if it is in C + +, maintains a m_cref), is designed to control the lifecycle of the interface or the lifecycle of the component (the component/interface also has a lifecycle), of course, We can also force the interface to the value nil can also release the interface, but that is not safe or should not be recommended. Here is the reason to use the reference technology as an example is to hope that you can understand the components of optimization, efficiency. The Frefcount is implemented in _addref and _release, and the following code (all of the code in this section is from Delphi6 as long as your reference version is DELPHI4 and the code is the same).
function Tinterfacedobject._addref:integer;
Begin
Result: = InterlockedIncrement (Frefcount);
End
function Tinterfacedobject._release:integer;
Begin
Result: = InterlockedDecrement (Frefcount);
If result = 0 Then
Destroy;
End
As we can see from the code, the lifecycle of the interface is controlled in the _addref and _release two methods, in fact, in component programming, these two aspects are specifically designed to control the lifecycle of the component (the Component lifecycle and Interface Lifecycle), which we will explain in one step. , they can be said to be meaningless, and reference counting variables (frefcount) are meaningless if they are not considered in the life cycle of the component.
AddRef and release is a memory management technique called reference counting, which is the simplest and most efficient way to make components delete components themselves. The COM component maintains a reference-counting variable to manage its lifecycle. When the customer obtains an interface from the component, the reference count variable is increased by 1 operations (_ADDREF), and when the client releases the call to the interface, the component automatically makes reference count minus 1 operations (_release) , in Delphi programming, we can not think about when to call these two methods, but if you are out of Delphi, you may have to consider when to call these two methods, such as in C + +, you must call the two methods themselves, This is why I write this section of the content. To put it simply, we don't need to think about reference counting, but in object references and interface references, you need to call both methods. It also involves the need to consider reference counting as a component is going to the entire release or individual release and the minimum unit release. For example, it encapsulates some COM objects for a COM component, but the problem arises when a user may need to invoke a service provided by several COM objects in a COM component through an interface. It is possible for a user to visit a COM object and then visit another COM object or interact with it. It is not fortunate that this component is also a large memory consumption component, especially when the user visited the two or more COM objects, how can you effectively manage the components? Does the user immediately release the COM object after they have accessed a COM object? Or is it a component-level release when the user finishes accessing the component? Or do you release the interface in more detail for each user that has not been used? This has a slight impact on the efficiency of the component. When we choose a different way, we may need to add our own reference counting variables for control, such as:
Var
The application of ofrefcount:integer;//object-level reference counting
Begin
.......
End
Var
cfrefcount:integer;//the application of the reference count at the component level.
Begin
......
End
or directly referencing the application count at the frefcount//interface level.
This is something we must consider. In the object model and the reference model, especially in their hybrid applications, if you also let Delphi for our automatic optimization (reference count of the call), then it will be a nightmare, disaster! OK, let's start with a discussion of these possible issues, or generalize to the optimization of reference counting.
First of all, we should understand that the general time when the two methods should be called, summed up as follows:
² You need to call _addref before returning to allow Frefcount to perform +1 operations. For those functions that return the pointer interface, the corresponding pointer should be _addref before returning. These functions include: QueryInterface, CreateInstance.
² After the use of the interface, the corresponding interface should be _release operation, the interface in the reslease of the release operation.
² calls the _addref method after assigning a value. The _addref of its corresponding pointer should be invoked before one of the interface pointers is assigned to another interface pointer. In other words, when calling another reference to an interface, you should increase the reference count of the corresponding component or interface pointer. The object model and reference model are obvious here.
In the previous article, I intentionally introduced two ways of COM objects in the diagram: Collection and containment, and this is a special example of COM components that we can not consider in reference counting. Remember to mention before, you can give the interface, the object of the forced release, as long as the simple to them to nil can be released. Reference counting as the chief executive of the lifecycle of a management component, in many places, trade-offs are needed. As shown in the following illustration:
For the above figure we are going to analyze the reference counting technique.
As a COM component, it can contain multiple COM objects, and the logical rules encapsulated by each COM object differ in size, such as COM object 1 and COM object 2 encapsulate a lot of logical rules, while COM object 3 is relatively simply encapsulating a few logical rules. If user A may now need the services provided by COM object 1 and COM object 3, and it has to access COM object 1 before the COM object 3 access, and if this COM component contains only the two COM objects, when the user has completed the COM object 1 access, After accessing COM object 3, do we still have COM object 1 in memory? And we have already said that in COM object 1 encapsulates more logical rules, it consumes a large amount of memory, COM object 3 also let exist? Of course, it's no longer necessary to exist, but how do we know at this point that its services are no more available to user A? As a component, it maintains a reference count for us at the component level, and when the service delivery of this component is completed, it is automatically released, but the COM object is not automatically released, so we can release it in the service application, as before, We can observe by defining a ofrefcount. The release of COM objects can be done so that more memory can be recycled and the efficiency of the components is improved, but in some cases it is not the same, in contrast, we call COM object 3 first and then COM object 3. Then there is no need for release at this time. So these are the things that we should think about and solve in the programming of components. Moreover, the situation encountered in the actual programming is far more complicated than the example we cite, if multiple objects coexist, it will be more complicated, but as long as we have some problems we can solve by reference counting, rather than simply letting the system complete these reference counts for us, learn to see for ourselves, Judgment is important in order to extrapolate, can really improve the efficiency of the component! At the same time, as a component, the interface of each object will not be given directly to the user, it can also be used as a common interface for the reference of other interfaces. Instance I will give.
Let's talk about the difference between the application of reference counting in object model and reference model.
We are familiar with the object model and the reference model, such as:
Var
The pt:tcoclass;//object model.
......
Var
pi:icoclass;//Reference Model.
......
In fact, the interface model has largely replaced the reference model, as in the two code, we can be in the program to make the call to COM objects, then we will use the AS operator, an object pointer assigned to or assigned to an interface pointer, at this time, Delphi when applied as, It will automatically call the _addref function. When the interface is finished, it calls the _release function, and the user's object is destroyed. As follows:
Procedure Dosomethingwithinterface (Intf:iformattednumber);
Begin
ShowMessage (intf.formattedstring);
End;
Procedure Createanduserobject;
Begin
Myinterger: = Tformattedinteger.create (12);
Dosomethingwithinterface (Myinteger as Iformattednumber);
Myinteger.setvalue (10);
End;
In this example, Myinteger is an object of a Tformattedinteger class. It is created by using the object model (that is, Tformattedinteger.create is assigned to an object variable). While invoking Dosomethingwithintegerface, the as operator (which is an obvious application of the object model, reference, or interface model) is used, and before the call as, Delphi is _addref, and after the call is finished , which is to be _release operation. At this point, the as transformation