Shanny introduced several methods for exporting data from the datagridview to excel, in which Microsoft. Office. Core. dll is used.
Microsoft Office 11.0 Object Library. The code is roughly as follows:
Private void executetransfer ()
{
Applicationclass app;
Try
{
APP = new applicationclass ();
Workbooks WBS = app. workbooks;
Workbook WB = WBS. Add (xlwbatemplate. xlwbatworksheet );
...
// Use 'app' to generate EXCEL object
}
Catch
{}
Finally
{
App. Quit ();
APP = NULL;
}
// GC. Collect (); Collect does not work here
}
Private void doexcecute ()
{
Executetransfer ();
GC. Collect (); // This collection is valid and excel.exe can be terminated.
}
Shanny said that although the app was released in finally, TASKMANAGER showed that the created excel. EXE process was not terminated. So we add
GC. Collect (), but it has no effect. Repeated tests show that GC. Collect () is valid only when GC. Collect () is used outside the method.
Q: After the app is set to null, the internal call of GC. Collect () in the method is invalid. It is valid only when the method is called out of the method?
Solution: This is the lifetime problem of COM Object running under CLR.
First, compare COM Object and. Net object.
1. The customer of COM object must manage the life time of COM object by themselves;. Net object is managed by CLR (GC)
2. The customer of COM ojbect calls QueryInterface to query whether COM Object supports an interface and obtains the interface pointer.
Use reflection to get the description, property, and method of the object.
3. the COM object is referenced by a pointer, and the position of the object in the memory remains unchanged. the. NET object can be collected by Compact during GC.
Heap to change the object location.
To realize the interaction between COM and. net,. net uses Wrapper Technology to provide RCW (runtime callable wrapper) and CCW (COM callable
Wrapper ).. When the net object calls the method of the COM object, the CLR will create an RCW object; when the COM Object calls the method of the. NET object, a CCW will be created.
Object.
1... Net calls COM components
The main functions of RCW:
1. RCW is A. Net class generated by runtime. It encapsulates the methods of the COM component and internally calls the COM component.
2. Parameters and return values of the marshal between. Net object and COM Object. Marshal method. For example
Conversion
3. CLR creates an RCW for each COM object, which is irrelevant to the number of references on the object. That is to say, each COM object has only one RCW object.
4. RCW contains the interface pointer of the COM Object and manages the reference count of the COM object. The release of RCW itself is managed by GC.
2. Memory Management of COM objects
COM objects are not created in the managed heap and cannot be searched and collected by GC. The COM Object uses the reference counting mechanism to release the memory.
1. As the package of the COM Object, RCW contains the interface pointer of the COM Object and carries out reference counting for this interface pointer. RCW itself as a. Net object is
Managed and collected by GC. When RCW is collected, its finalizer releases the interface pointer and destroys the COM object.
In the above Code, by setting APP = NULL, the. NET object that references RCW is reduced by 1, but RCW still exists. At this time, GC. Collect () is called directly (),
It seems that you should collect RCW and release COM objects. But why must GC. Collect () be called outside the method?
The reason is that in the executetransfer () method, besides the app, WBS and WB objects use the same COM object, and the COM object only
There is an RCW object. However, WBS, WB, and any other variables pointing to this COM object will produce references to RCW.
When GC. Collect () is called inside the method, we only set APP = NULL, while other COM Object Reference variables are not set to null, GC naturally cannot receive
When the method ends, the lifecycle of WBS and WB ends, and their reference to RCW does not exist. At this time, GC can collect RCW, and the COM object is also
It is released.
Therefore, we need to set all the variables in the code that reference COM objects (WBS, WB, and so on) to null to eliminate references to RCW, so that we can
To allow the GC to collect data to RCW, and then release the COM object. As follows:
// Modified
Private void executetransfer ()
{
Applicationclass app;
Try
{
APP = new applicationclass ();
Workbooks WBS = app. workbooks;
Workbook WB = WBS. Add (xlwbatemplate. xlwbatworksheet );
...
// Use app to generate EXCEL object
}
Catch
{}
Finally
{
App. Quit ();
APP = NULL;
// Eliminate all references to RCW, otherwise GC. Collect () cannot be collected to RCW
WBS = NULL;
WB = NULL;
// Other variables referenced to the COM object are set to null.
}
GC. Collect (); // valid
}
2. Due to the uncertainty of GC collection time (because the COM object is released after RCW finalizer is executed, even if RCW is collected
This will cause the COM object to stay in the memory before the RCW is collected. If the COM Object occupies a large memory or resource
A limited number of sources (filehandle, dbconnection) may cause memory leakage or program exceptions.
INT system. runtime. interopservices. Marshal. releasecomobject (Object O) can release the corresponding com before GC collects RCW.
Object.
The parameter of this method must be the RCW type that references the COM object, such as app, WBS, and WB in this example.
After this method is called, RCW releases the interface pointer, which is an empty wrapper. its connection with the COM object is broken, and then it is called.
Runtime error. At this time, the COM object will be released. (This is the work of RCW)
Shanny also mentioned that even if system. runtime. interopservices. Marshal. releasecomobject (APP) is called, why can't it be released?
COM object?
The reason is that all referenced variables such as WBS and WB must be release to release the corresponding COM object.
// Modified
Private void executetransfer ()
{
Applicationclass app;
Try
{
APP = new applicationclass ();
Workbooks WBS = app. workbooks;
Workbook WB = WBS. Add (xlwbatemplate. xlwbatworksheet );
...
// Use app to generate EXCEL object
}
Catch
{}
Finally
{
App. Quit ();
System. runtime. interopservices. Marshal. releasecomobject (APP );
System. runtime. interopservices. Marshal. releasecomobject (WBS );
System. runtime. interopservices. Marshal. releasecomobject (WB );
// Other interface pointers referenced to COM objects... release
}
}
This avoids explicitly calling GC. Collect ().
Question:
1. Internal internaling count in RCW is different from the reference count of COM. After the releasecomobject method is called
Internal implements aling count decrease. When the value is 0, the reference count of the COM Object decreases.
2. the return value of the releasecomobject () method. Its return value is an integer, which is the internal internaling count of RCW. When it decreases to 0
The reference count of the COM object will decrease. Generally, the internal internaling count of an interface pointer of RCW will not exceed 1
When will this value be greater than 1? Msdn explains this as follows: when the pointer to the com iunknown interface is changed from unmanged
The value of the managed interface increases progressively. For example:
Applicationclass APP = new applicationclass ();
Odbcerrors err = app. odbcerrors;
Err = app. odbcerrors;
Err = app. odbcerrors; // In fact, this is rarely written. In the case of multithreading, similar cases may occur, but no examples can be written.
...
Int I = system. runtime. interopservices. Marshal. releasecomobject (ERR );
At this time, I = 2; then it loops until internal marshaling count is 0
While (marshal. releasecomobject (ERR )! = 0 );
Legacy problems:
Applicationclass APP = new applicationclass ();
Workbooks WBS = app. workbooks;
WBS = app. workbooks;
WBS = app. workbooks;
...
Int I = system. runtime. interopservices. Marshal. releasecomobject (APP );
Int J = system. runtime. interopservices. Marshal. releasecomobject (WBS );
At this time, both I and J are 0, But Com still cannot be released, and I don't know who should release at this time?
3. applicationclass. Quit () method
What is the purpose?
Appendix:
Com calls. Net object
The main functions of CCW:
1. CCW is actually a COM component generated by runtime. It is registered in the Registry and has CLSID and IID. It implements the interface and contains the. NET object
Call.
2. Call between the marshal. Net object and the COM Client.
3. Each. Net object has only one CCW, and multiple com customers call the same CCW.
4. the COM Client calls the CCW as a pointer, so the CCW is allocated to the non-collected stack and is not managed by runtime. The. NET object is allocated in
Garbage-collected stack, managed by runtime, enjoy the advantages of CLR.
5. CCW is actually a COM component, so it follows the reference counting rule. When its reference count is 0, it releases its reference to the. NET object it manages, and
Release your memory. When the reference count of the. NET object is 0, it will be recycled by GC.
From http://whatsthematrix.spaces.live.com/Blog/cns! 52a...