I wrote code that overrides object's Equals.
I realized, after I wrote it, that I'm going to have StackOverFlowException since I didn't yet implemented the IEquatable interface to handle the last line of code. Yet, I run the code to see what happen, and some strange thing happen, you can see for yourself in the following image:
The breakpoint isn't even hittable at this moment, seems like the code is being used even before my program is run. Is it something that is done by the CLR ? Is it something else ?
Thanks for the help !
The stack is exhausted (the very last straw that breaks camel's back) on
if (ReferenceEquals(right, null))
probably, the stack doesn't have another 4 (8) bytes to store right.
The actual reason seems to be at
return Equals(right as Quality)
if right is of Quality type, the code is doomed to call Equals again and again
Related
I've got a method that I'm calling ... well, very often. And now the GC is becoming a problem, because apparently this method is creating garbage, but I can't seem to figure out why.
Item item;
foreach (Point3D p in Point3D.AllDirections)
{
item = grid[gridPosition + p];
if (item != null && item.State != State.Initialized)
else
return;
}
OtherMethod(this);
This method is inside the Item class and figures out the state of neighbouring items. The gridPosition variable is obviously the position of this item inside the grid and the Point3D is a struct that just contains 3 ints, one for each axis. It also contains a few predefined static arrays such as AllDirections which itself only contains Point3Ds.
Now, the state of items can change at any time and once all neighbours have a specific state (or rather aren't in the Initialized state) I do some other stuff (OtherMethod), which also changes the state of the item so this method is no longer called. As such the produced garbage is only a problem when neighbours don't change their state (for example when there is no user input). I guess you could think of this as a substitution for an event driven system.
I admit that I have a rather limited understanding of memory management and I tend to only really understand things by doing them, so reading up on it didn't really help me much with this problem. However, after reading about it I got the impression that every value type, that is defined within a method and doesn't leave it, will be collected upon leaving the method. So I have a little trouble figureing out what's actually left after the return.
Any ideas on what's actually generating the garbage here ? Of course the best case would be to produce no garbage at all, if at all possible.
(Just in case this is relevant, I'm working in Unity and the method in question is the Monobehaviour Update)
Edit for all the comments:
Holy cow you guys are quick. So...
# Jeppe Stig Nielsen: There is nothing between if and else, there was once but I didn't need that anymore. It's just a quick way to leave if no neighbour was found. Also, Indexer ! Completely forgot about that, here it is:
public Item this[Point3D gridPosition]
{
get
{
Item item;
items.TryGetValue(gridPosition, out item);
return item;
}
}
Could the TryGetValue be the reason ?
# Luaan: I already tried a normal for loop, didn't change anything. That looked something like this:
for (int i = 0; i < 6; i++)
{
item = grid[gridPosition + Point3D.AllDirections[i]];
}
If it was the enumerator, that should've fixed it, no ?
# Rufus: Yes that's a better way to write the if, will fix that. The whole thing is a work in progress right now, so that's just a remnant of past experimentation. There is currently is nothing else in the if statement.
# Tom Jonckheere: Well there isn't really much else. It's just Unitys Update() followed by two if statements for the State. And that's really just because I currently only work with two states but have already setup more, so someday there will probably be a switch instead of ifs.
# Adam Houldsworth: Well yes, the problem is certainly that I call it so often. The odd thing is, the amount of garbage produced varies wildly. As far as I can tell it's in the range of 28 bytes to 1.8KB. As for the whole red herring thing, I don't think that's the case. The profiler points to the Update method, which only contains two ifs, one which is the code from above, the other one isn't being used when no state changes occur. And when testing, there are no state changes, except for intial setup.
Also, sorry for the wrong tag, first time I've visited this site. Looks like I'll have some reading to do :)
foreach calls GetEnumerator, which, in turn, creates a new instance of Enumerator every time it's called.
So after Jeppe Stig Nielsen and Luaan made me remember that I'm infact using an indexer I did some googleing and found out that this is not a new issue. Apparently Dictonary.TryGetValue works by calling Equals(object o) on the keys. Now these have to be unboxed which, as far as I understand it, creates the garbage. I now followed the advice I found on Google and implemented the IEquatable interface in my Point3D struct, which does not requiere any boxing. And as it turns out, a big chunk of the garbage is gone.
So the generated garbage per call went from ~28B-1.8KB down to ~28B-168B. Which is pretty good, no more GC spikes. Though I'm still curious where the rest of the garbage is coming from.
Anyway, this was already a big help, so thanks for your answers guys.
Edit: Figured out where the rest of the garbage was comeing from. I just called base.GetHashCode, because I didn't know any better. I did some research into pretty much everything related to hash codes and then implemented it correctly. And now I'm down to exactly 0 bytes of garbage. Pretty neat.
So, I have a piece of code using WeakReferences. I know of the common .IsAlive race condition, so I didn't use that. I basically have something like this:
WeakReference lastString=new WeakReference(null);
public override string ToString()
{
if(lastString!=null)
{
var s=lastString.Target as string; //error here
if(s!=null)
{
return s;
}
}
var str=base.ToString();
lastString=new WeakReference(str);
return str;
}
Somehow, I'm getting a null reference exception at the marked line. By debugging it, I can confirm that lastString is indeed null, despite being wrapped in a null check and lastString never actually being set to null.
This only happens in a complex flow as well, which makes me think garbage collection is somehow taking my actual WeakReference object, and not just it's target.
Can someone enlighten me as to how this is happening and what the best course of action is?
EDIT:
I can't determine at all the cause of this. I ended up wrapping the error code in a try-catch just fix it for now. I'm very interested in the root cause of this though. I've been trying to reproduce this in a simple test case, but it's proven very difficult to do. Also, this only appears to happen when running under a unit test runner. If I take the code and trim it down to the minimum, it will continue to crash when running using TestDriven and Gallio, but will not fail when put into a console application
This ended up being a very hard to spot logic bug that was in plain sight.
The offending if statement really was more like this:
if(lastString!=null && limiter==null || limiter=lastLimiter)
The true grouping of this is more like this:
if((lastString!=null && limiter==null) || limiter=lastLimiter)
And as Murphy's law would dictate, somehow, in this one unrelated test case, lastLimiterand lastString got set to null by a method used no where but this one single test case.
So yea, no bug in the CLR, just my own logic bug that was very hard to spot
It's very clear in the debugger that the dictionary is populated with the values; so why does it not even ENTER the loop at all? I've tried stepping through and I get nothing. It just skips over the loop. Period. I use similar techniques elsewhere and have no issues. This is all on the same thread so I don't understand.
You can see a video of some of the frustration here: http://youtu.be/XernyY5-BAo
I expect the name == e.Name is false
The compiler probably optimized stepping in this case.
or maybe name is null and it has an exception?
I hate to be that guy and answer my own question but I feel like someone else could learn something from my error.
It turns out, the EntityManager from the base class was implemented separately by the base class in this case, it was over-ridden with the new keyword. This was causing the lists to separate and cause all sorts of ugly issues. Don't hide your inheritance trees, everyone! Always double check your implementations! Thanks for all the help everyone; I still don't know why Visual Studio was displaying different values than it should have so if anyone has any information pertaining to why this might be the case - I'll mark you best answer!
I got an OutOfMemoryException earlier and couldn't figure out what it was for. It made no sense at all. Dug around in my code, and suddenly remembered that somewhere had forgotten to check for null, and in this particular case it was (and should be) exactly that. That shouldn't cause an OutOfMemoryException in my opinion, but I fixed it anywas of course. And when I did, the exception didn't appear anymore!
So I removed the check again and studied the exception I got some more. And turns out it had an InnerException of type NullReferenceException and a stack trace which of course made a lot more sense.
But why did I get an OutOfMemoryException? This has never happend to me before... makes no sense to me...
Would love to give some more context, but can't really say much without having to upload the whole project, which I can't (And which you wouldn't want to read through anyways :p). But the specific place it happend looks like this:
{
foreach (var exportParameter in exportParameters)
{
// Copy to local
var ep = exportParameter;
// Load stored values from db
...
}
int i = 1;
exportParameters
.OrderBy(ø => ø.Sequence)
.ForEach(ø => { if (!ø.Locked) ø.Sequence = i++; });
}
The fix was to put an if(exportParameters != null) before the code block. exportParameters is a List<ExportParameter>, except in the failing case in which it was null.
You might be facing the problem that Constrained Execution Regions are designed to prevent - that is, the JITting of some code that your catch clause relies on is causing the out of memory condition.
(In response to svish's comment, this is the first link when googling the phrase: http://msdn.microsoft.com/en-us/library/ms228973.aspx)
Aside from the obvious reason for getting an OOMException, you can also get it if you still have memory available, just not a big enough chunk for what is being requested. If you're getting it reliably and relatively near startup, you're probably accidentally requesting more memory than you intend to (ie. requesting a very large array). Can you post a bit of your code or at least describe your allocation pattern?
So I have this code that takes care of command acknowledgment from remote computers, sometimes (like once in 14 days or something) the following line throws a null reference exception:
computer.ProcessCommandAcknowledgment( commandType );
What really bugs me is that I check for a null reference before it, so I have no idea whats going on.
Here's the full method for what its worth:
public static void __CommandAck( PacketReader reader, SocketContext context )
{
string commandAck = reader.ReadString();
Type commandType = Type.GetType( commandAck );
Computer computer = context.Client as Computer;
if (computer == null)
{
Console.WriteLine("Client already disposed. Couldn't complete operation");
}
else
{
computer.ProcessCommandAcknowledgment( commandType );
}
}
Any clues?
Edit: ProcessCommandAcknowledgment:
public void ProcessCommandAcknowledgment( Type ackType )
{
if( m_CurrentCommand.GetType() == ackType )
{
m_CurrentCommand.Finish();
}
}
Based on the information you gave, it certainly appears impossible for a null ref to occur at that location. So the next question is "How do you know that the particular line is creating the NullReferenceException?" Are you using the debugger or stack trace information? Are you checking a retail or debug version of the code?
If it's the debugger, various setting combinations which can essentially cause the debugger to appear to report the NullRef in a different place. The main on that would do that is the Just My Code setting.
In my experience, I've found the most reliable way to determine the line an exception actually occurs on is to ...
Turn off JMC
Compile with Debug
Debugger -> Settings -> Break on Throw CLR exceptions.
Check the StackTrace property in the debugger window
I would bet money that there's a problem with your TCP framing code (if you have any!)
"PacketReader" perhaps suggests that you don't. Because, technically, it would be called "FrameReader" or something similar if you did.
If the two PC's involved are on a local LAN or something then it would probably explain the 14 days interval. If you tried this over the Internet I bet your error frequency would be much more common especially if the WAN bandwidth was contended.
Is it possible that ReadString() is returning null? This would cause GetType to fail. Perhaps you've received an empty packet? Alternatively, the string may not match a type and thus commandType would be null when used later.
EDIT:
Have you checked that m_CurrentCommand is not null when you invoke ProcessCommandAcknowledgment?
What are the other thread(s) doing?
Edit: You mention that the server is single threaded, but another comment suggests that this portion is single threaded. If that's the case, you could still have concurrency issues.
Bottom line here, I think, is that you either have a multi-thread issue or a CLR bug. You can guess which I think is more likely.
If you have optimizations turned on, it's likely pointing you to a very wrong place where it actually happens.
Something similar happened to me a few years back.
Or else a possible thread race somewhere where context gets set to null by another thread. That would also explain the uncommonness of the error.
Okay, ther are really only a few possibilities.
Somehow your computer reference is being tromped by the time you call that routine.
Something under the call is throwing the null pointer dereference error but it's being detected at that line.
Looking at it, I'm very suspicious the stack is getting corrupted, causing your computer automatic to get mangled. Check the subroutine/method/function calls around the one you have trouble with; in particular, check that what you're making into a "Computer" item really is the type you expect.
computer.ProcessCommandAcknowledgment( commandType );
Do you have debugging symbols to be able to step into this?
The null ref exception could be thrown by ProcessCommandAcknowledgement, and bubble up.