This is a logging class with a constructor:
public QFXLogger(
int maxFileSize,
TraceLevel logLevel)
{
this.maxFileSize = maxFileSize;
logSwitch.Level = logLevel;
//Configure log listener
traceListener = new FileLogTraceListener();
traceListener.DiskSpaceExhaustedBehavior = DiskSpaceExhaustedOption.DiscardMessages;
traceListener.CustomLocation = #".\Log";
traceListener.BaseFileName = "QFXLog";
traceListener.AutoFlush = true;
//Remove all other listeners
Trace.Listeners.Clear();
//Add QFX listener
Trace.Listeners.Add(traceListener);
//Write header
WriteSessionHeader();
}
And this is the destrcutor:
~QFXLogger()
{
WriteSessionFooter();
traceListener.Close();
}
I just want to write a footer to the underlying stream before the logger gets GC.
Without the destructor everything is fine, but with it I get the following:
Unhandled Exception: System.ObjectDisposedException: Cannot access a closed file
.
at System.IO.__Error.FileNotOpen()
at System.IO.FileStream.Flush(Boolean flushToDisk)
at System.IO.FileStream.Flush()
at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
at System.IO.StreamWriter.Flush()
at Microsoft.VisualBasic.Logging.FileLogTraceListener.ReferencedStream.CloseS
tream()
at Microsoft.VisualBasic.Logging.FileLogTraceListener.CloseCurrentStream()
at Microsoft.VisualBasic.Logging.FileLogTraceListener.Write(String message)
at System.Diagnostics.TraceInternal.Write(String message)
at System.Diagnostics.Trace.Write(String message)
at QFXShell.QFXLogger.WriteSessionFooter()
at QFXShell.QFXLogger.Finalize()
It seems to me that the underlying stream was already closed.
How can I suppress this closing(of the underlying stream) or is this another issue?
Finalizers (destructors) in c# should not be used in this method. Finalizers are intended only to release unmanaged resources. When a finalizer is called, access to other .net objects is not guaranteed and should only release unmanaged resources that you directly allocated.
Finalize operations have the following limitations:
The finalizers of two objects are not guaranteed to run in any specific order, even if one object refers to the other. That is, if Object A has a reference to Object B and both have finalizers, Object B might have already finalized when the finalizer of Object A starts.
What you need to do is implement the IDisposable Interface to properly close your logging file. Some additional information can be found at Kelly Leahy's IDisposable and Garbage Collection.
If you are not in a situation where a disposable class will help (global object, etc.) you can always implement a Close method yourself to ensure the file is valid before it is released.
It is too late for you to close the tracer object in the destructor. In this moment a lot of objects which are not needed any more can be already disposed.
I would propose to implement a IDisposable interface with a public Dispose method and to call this method as soon as you know that you are not going to need this QFXLogger object any more. In this Dispose method, I would check if the tracer object is not NULL, open and then I would call Close on it.
See Proper use of the IDisposable interface for more details.
Related
I am writing error to event log but when i checked for leakage i got event log leakage in .net profiler, Do I need to dispose this object? Is it will create any issue in multi threading?
public override void ProcessWarning(string title, string message)
{
if (title == null)
eventLog.WriteEntry(message, EventLogEntryType.Warning);
else
eventLog.WriteEntry(title + '\n' + message, EventLogEntryType.Warning);
}
}
The EventLog class extends Component, which shows that it implements IDisposable. So yes, you will need to (eventually) Dispose() of it.
Apparently your eventLog is a field in your class. This (an IDisposable field) means that your class needs to implement IDisposable itself. In your own Dispose method you will then need to dispose of that eventLog.
And of course this means that anything using this class must treat it as the IDisposable that it now is.
The following two lines of code execute one right after the other:
this.dataWriter.WriteBytes(message.MessageBuffer);
await this.dataWriter.StoreAsync();
Although the WriteBytes call completes without exception, the StoreAsync call right below it bombs with a ObjectDisposedException and says
The object has been closed. (Exception from HRESULT: 0x80000013)
this.DataWriter (Windows.Storage.Streams.DataWriter) is not null, so what exactly is it saying is "closed?"
EDIT
Just for some further context on how the object is created
this.socket = new StreamSocketListener();
this.socket.ConnectionReceived += this.EventSocketConnectionReceived;
private void EventSocketConnectionReceived(StreamSocketListener sender,
StreamSocketListenerConnectionReceivedEventArgs args)
{
if (this.dataWriter == null)
{
this.dataWriter = new DataWriter(args.Socket.OutputStream);
}
}
I have no experience with Windows.Storage.Streams.DataWriter, but my bet is that you're passing it a stream, then closing it, then calling this. It's probably not the dataWriter that's even throwing the exception, although glancing at the Stack Trace would tell you.
This code would cause this error, and it's a pretty easy mistake to make:
Windows.Storage.Streams.DataWriter dataWriter;
using (var file = File.OpenRead("..."))
{
dataWriter = new DataWriter(file);
}
dataWriter.WriteBytes(message.MessageBuffer);
await dataWriter.StoreAsync();
Disposal has little to directly do with null. There's rarely much to do with something that's disposed, so we make it null, but that's not necessary.
I'd check around to see what stream you're passing into the constructor, and then look for any references to that stream that might be disposing it (either through a using block like I showed here, or an explicit call to stream.Dispose()).
There are an infinite combination of lines to throw it, and it's unlikely that what you've got is as simple as anything I'm saying here (it's probably spread across constructors and methods, and mixed in with unrelated code). But I'd virtually guarantee that it's something like this pattern.
Just since it sounds like there's some disagreement, the issue here is that it's difficult to tell if something is disposed without telling it to do something.
Because DataWriter is essentially caching up operations, it doesn't talk to the underlying stream until you call StoreAsync(). That's why WriteBytes isn't async, as well. You can imagine an implementation that just pins them onto a List<byte> (although it'd be much more complicated than that, of course).
But when you do call the StoreAsync() method, it reaches out to the stream and says "write this stuff I have cached up." The stream tries, but it's already been closed, so it throws that exception.
That's why it doesn't throw on the first line, but does on the second. And why I'm hazarding the guess that this is a disposed stream, as compared to the DataWriter itself being disposed.
Per your edit and comment, your stream is coming from event args.
My guess is that the stream is getting closed by the event caller, or else the socket is getting closed by the remote client (perhaps due to a timeout?). I don't know whether there's a right way to persist that stream, if it is the former. But that's probably where you should put your research time.
I have a class that implements IDisposable, because it uses image resources (Bitmap class) from GDI+. I use it for wrapping all that gimmicky LockBits/UnlockBits. And it works fine, be it when I call Dispose() or with the using statement.
However, if I leave the program to terminate without disposing, I get a System.AccessViolationException. Intuitively, I think the GC would call the Dispose the same way I do, and the object would gracefully release the resources, but that's not what happening. Why?
Here's the IDisposable code:
private bool _disposing = false;
~QuickBitmap() {
Dispose(false);
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool safeDispose) {
if (_disposing)
return;
SaveBits(); // private wrapper to UnlockBits
bytes = null; // byte[] of the image
bmpData = null; // BitmapData object
if (safeDispose && bm != null) {
bm.Dispose(); // Bitmap object
bm = null;
}
_disposing = true;
}
Here's when it works ok:
using (var qbm = new QuickBitmap("myfile.jpg"))
{
// use qbm.GetPixel/qbm.SetPixel at will
}
Here's when it doesn't work:
public static void Main (string[] args) {
// this is just an example, simply constructing the object and doing nothing will throw the exception
var qbm = new QuickBitmap(args[0]);
qbm.SetPixel(0, 0, Color.Black);
qbm.Save();
}
The complete excetion is (there's no inner exception):
An unhandled exception of type 'System.AccessViolationException' occurred in mscorlib.dll
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
The reproduction is 100%, even on different machines. I do figure out we should use using or Dispose(), not using it is bad and all that stuff. I just want to know: why does this happen? Why is the memory "protected"? Which kind of access am I violating?
The problem occurs because you included an unnecessary finalizer in your implementation. Code executed from a finalizer generally cannot access managed objects safely. It is likely that the call to SaveBits results in the use of managed objects in violation of this rule, though you did not include the code for that method.
The best solution would be to simply remove the finalizer from QuickBitmap, since the QuickBitmap class does not directly own unmanaged resources.
The whole point of IDisposable is to gracefully clean up unmanaged resources. The literal definition of an unmanaged resource is a resource that the GC won't be able to clean up on its own. Unsurprisingly, it won't be able to clean it up on its own if you don't. Objects that can be cleaned up entirely through the GC need not be disposable, and this require no manual disposal. If the object could be cleaned up without manual disposable then it wouldn't have a need to implement IDisposable in the first place.
I have the weirdest problem, and most likely there is something I am missing or I don't know.
I created a C# COM interface/class that for this question we'll call it: Ics_obj and Ccs_obj.
In the destructor of the object I added a trace to the output debug:
~Ccs_obj()
{
OutputDebugString("Releasing: "+this.GetHashCode()); // OutputDebugString with p/invoke
}
That I wrote a C++ class that Ics_obj is a member in that class, and the member is the com_ptr_t wrapper of Ics_obj generated in the .tlh:
class lib_exp_macro cpp_client
{
public:
cpp_client();
~cpp_client();
...
...
Ics_objPtr _csobj; // the Ics_obj* wrapped in com_ptr_t.
}
In the constructor I create an instance of Ccs_obj, and in the destructor I release it. I also added the following traces:
cpp_client::cpp_client()
{
HRESULT hr = _csobj.CreateInstance( __uuidof( Ccs_obj ) );
if(FAILED(hr)){ /* throw exception */ }
OutputDebugString("Creating client");
}
cpp_client::~cpp_client()
{
OutputDebugString("before releasing _csobj");
}
Now, I have created 2 instances of cpp_client through my code (creating them with the same thread during initialization of my application), and I get 2 traces of "Creating Client".
The problem is that during shutdown I get ACCESS VIOLATION and the traces are as follow:
before release // first object being released
Releasing: (some number X)
Releasing: (some number Y, Y != X) // <- where did that come from?
before releasing _csobj
SYSTEM CRASH HORRIBLY WITH ACCESS VIOLATION! :-(
When I debug I get ACCESS VIOLATION for accessing the v-table of the COM object.
Does anyone know why I get ACCESS VIOLATION? what am I doing wrong? I am REALLY LOST HERE! :-(
Thanks in advance!
UPDATE:
With the help of two answers (that were deleted), I understood more things, but I still have open questions...
First and the most important thing is that the 2nd release was in dllmain PROCESS_DETACH. When I moved the release code out of this context, everything was fine, but why can't I release the COM object in the PROCESS_DETACH context?!
One of the answers that were deleted said that CLR of the .Net has shutdown, therefore the 2nd release in my traces. This made a lot of sense and what lead me into moving the releasing code out of PROCESS_DETACH context, but if it is so and CLR does shutdown because the PROCESS_DETACH code, why don't I get any of the "Releasing: ..." traces if I'm not releasing the COM object (by detaching _com_ptr_t)??? Or in other words, why does CLR doesn't shutdown if I don't release the 1st object?
Thanks again for your amazing help!
(I know, this is a ridiculously long question. I tried to separate the question from my investigation so far, so it's slightly easier to read.)
I'm running my unit tests using MSTest.exe. Occasionally, I see this test error:
On the individual unit test method: "The agent process was stopped while the test was running."
On the entire test run:
One of the background threads threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
at System.Runtime.InteropServices.Marshal.ReleaseComObject(Object o)
at System.Management.Instrumentation.MetaDataInfo.Dispose()
at System.Management.Instrumentation.MetaDataInfo.Finalize()
So, here's what I think I need to do: I need to track down what is causing the error in MetaDataInfo, but I'm drawing a blank. My unit test suite takes over half an hour to run, and the error doesn't happen every time, so it's hard to get it to reproduce.
Has anyone else seen this type of failure in running unit tests? Were you able to track it down to a specific component?
Edit:
The code under test is a mix of C#, C++/CLI, and a little bit of unmanaged C++ code. The unmanaged C++ is used only from the C++/CLI, never directly from the unit tests. The unit tests are all C#.
The code under test will be running in a standalone Windows Service, so there's no complication from ASP.net or anything like that. In the code under test, there's threads starting & stopping, network communication, and file I/O to the local hard drive.
My investigation so far:
I spent some time digging around the multiple versions of the System.Management assembly on my Windows 7 machine, and I found the MetaDataInfo class in System.Management that's in my Windows directory. (The version that's under Program Files\Reference Assemblies is much smaller, and doesn't have the MetaDataInfo class.)
Using Reflector to inspect this assembly, I found what seems to be an obvious bug in MetaDataInfo.Dispose():
// From class System.Management.Instrumentation.MetaDataInfo:
public void Dispose()
{
if (this.importInterface == null) // <---- Should be "!="
{
Marshal.ReleaseComObject(this.importInterface);
}
this.importInterface = null;
GC.SuppressFinalize(this);
}
With this 'if' statement backwards, MetaDataInfo will leak the COM object if present, or throw a NullReferenceException if not. I've reported this on Microsoft Connect: https://connect.microsoft.com/VisualStudio/feedback/details/779328/
Using reflector, I was able to find all uses of the MetaDataInfo class. (It's an internal class, so just searching the assembly should be a complete list.) There is only one place it is used:
public static Guid GetMvid(Assembly assembly)
{
using (MetaDataInfo info = new MetaDataInfo(assembly))
{
return info.Mvid;
}
}
Since all uses of MetaDataInfo are being properly Disposed, here's what's happening:
If MetaDataInfo.importInterface is not null:
static method GetMvid returns MetaDataInfo.Mvid
The using calls MetaDataInfo.Dispose
Dispose leaks the COM object
Dispose sets importInterface to null
Dispose calls GC.SuppressFinalize
Later, when the GC collects the MetaDataInfo, the finalizer is skipped.
.
If MetaDataInfo.importInterface is null:
static method GetMvid gets a NullReferenceException calling MetaDataInfo.Mvid.
Before the exception propagates up, the using calls MetaDataInfo.Dispose
Dispose calls Marshal.ReleaseComObject
Marshal.ReleaseComObject throws a NullReferenceException.
Because an exception is thrown, Dispose doesn't call GC.SuppressFinalize
The exception propagates up to GetMvid's caller.
Later, when the GC collects the MetaDataInfo, it runs the Finalizer
Finalize calls Dispose
Dispose calls Marshal.ReleaseComObject
Marshal.ReleaseComObject throws a NullReferenceException, which propagates all the way up to the GC, and the application is terminated.
For what it's worth, here's the rest of the relevant code from MetaDataInfo:
public MetaDataInfo(string assemblyName)
{
Guid riid = new Guid(((GuidAttribute) Attribute.GetCustomAttribute(typeof(IMetaDataImportInternalOnly), typeof(GuidAttribute), false)).Value);
// The above line retrieves this Guid: "7DAC8207-D3AE-4c75-9B67-92801A497D44"
IMetaDataDispenser o = (IMetaDataDispenser) new CorMetaDataDispenser();
this.importInterface = (IMetaDataImportInternalOnly) o.OpenScope(assemblyName, 0, ref riid);
Marshal.ReleaseComObject(o);
}
private void InitNameAndMvid()
{
if (this.name == null)
{
uint num;
StringBuilder szName = new StringBuilder {
Capacity = 0
};
this.importInterface.GetScopeProps(szName, (uint) szName.Capacity, out num, out this.mvid);
szName.Capacity = (int) num;
this.importInterface.GetScopeProps(szName, (uint) szName.Capacity, out num, out this.mvid);
this.name = szName.ToString();
}
}
public Guid Mvid
{
get
{
this.InitNameAndMvid();
return this.mvid;
}
}
Edit 2:
I was able to reproduce the bug in the MetaDataInfo class for Microsoft. However, my reproduction is slightly different from the issue I'm seeing here.
Reproduction: I try to create a MetaDataInfo object on a file that isn't a managed assembly. This throws an exception from the constructor before importInterface is initialized.
My issue with MSTest: MetaDataInfo is constructed on some managed assembly, and something happens to make importInterface null, or to exit the constructor before importInterface is initialized.
I know that MetaDataInfo is created on a managed assembly, because MetaDataInfo is an internal class, and the only API that calls it does so by passing the result of Assembly.Location.
However, re-creating the issue in Visual Studio meant that it downloaded the source to MetaDataInfo for me. Here's the actual code, with the original developer's comments.
public void Dispose()
{
// We implement IDisposable on this class because the IMetaDataImport
// can be an expensive object to keep in memory.
if(importInterface == null)
Marshal.ReleaseComObject(importInterface);
importInterface = null;
GC.SuppressFinalize(this);
}
~MetaDataInfo()
{
Dispose();
}
The original code confirms what was seen in reflector: The if statement is backwards, and they shouldn't be accessing the managed object from the Finalizer.
I said before that because it was never calling ReleaseComObject, that it was leaking the COM object. I read up more on the use of COM objects in .Net, and if I understand it properly, that was incorrect: The COM object isn't released when Dispose() is called, but it is released when the garbage collector gets around to collecting the Runtime Callable Wrapper, which is a managed object. Even though it's a wrapper for an unmanaged COM object, the RCW is still a managed object, and the rule about "don't access managed objects from the finalizer" should still apply.
Try to add the following code to your class definition:
bool _disposing = false // class property
public void Dispose()
{
if( !disposing )
Marshal.ReleaseComObject(importInterface);
importInterface = null;
GC.SuppressFinalize(this);
disposing = true;
}
If MetaDataInfo uses the IDisposable pattern, then there should also be a finalizer (~MetaDataInfo() in C#). The using statement will make sure to call Dispose(), which sets the importInterface to null. Then when the GC is ready to finalize, the ~MetaDataInfo() is called, which would normally call Dispose (or rather the overload taking a bool disposing: Dispose(false)).
I would say that this error should turn up quite often.
Are you trying to fix this for your tests? If so, rewrite your using. Don't dispose of it yourself but write some code to use reflection to access the private fields and dispose of them correctly and then call GC.SuppressFinalize to prevent the finalizer from running.
As a brief aside (loved your investigation btw) you state that Dispose calls Finalize. It's the other way round, Finalize when invoked by the GC calls Dispose.