I'm trying to make a Tetris-like game in XNA, and currently I'm thinking of what way would be the best to handle it.
This is what I have so far:
I have a class called Block, which has for example texture and color tint.
Then I was planning on having everything in a double array, like:
Block[,] blocks = new Block[10,20];
which would then be the full grid.
And then when the blocks move downwards, I was thinking of doing like this:
blocks[x,y+1] = blocks[x,y];
blocks[x,y] = null;
At first I thought this was a good idea, but now when I've been thinking I'm not so sure. How does it work with the memory and such? Does it create a new object every time I do that or what? Could someone please explain how it actually works when I move an object inside an array?
I'm not really looking for a Tetris-specific answer, I'm just interested in how it actually works.
Thanks.
No, you're just moving pointers around. When you say:
blocks[x,y+1] = blocks[x,y];
what you're essentially doing is swapping the pointer. The object will stay exactly where it is, but now instead of it being at index x,y it'll be at index of x , y+1. When you say
blocks[x,y] = null;
there you're removing the reference to the object x,y and if nothing else is holding a reference, the Garbage Collecter will clean it up.
The first answer above is almost correct, but the assignment is not swapping the pointer, it is duplicating it. After the first line of code there are two references to the object originally referenced at blocks[x,y]. The null assignment removes the original reference, but you still have the new reference living at blocks[x,y+1]. Null that one and the heap object will be fair game for the GC.
If you were storing value types (such as int, string) inside your array, you would indeed be creating a copy of the data each time you copied a value over, because value types are immutable in C#. Since you're storing a class (which is a reference type) in your array, your code is really just making a copy of the pointer, not the whole object.
Related
I have a large T[] in generation 2 on the Large Object Heap. T is a reference type. I make the following assignment:
T[0] = new T(..);
Which object(s) are marked as dirty for the next Gen0/Gen1 mark phases of GC? The entire array instance, or just the new instance of T? Will the next Gen0/Gen1 GC mark phase have to go through every item of the array? (That would seem unnecessary and very inefficient.)
Are arrays special in this regard? Would it change the answer if the collection were e.g. a SortedList<K, T> and I added a new, maximal item?
I've read through many questions and articles, including the ones below, but I still don't think I've found a clear answer.
I'm aware that an entire range of memory is marked as dirty, not individual objects, but is the new array entry or the array itself the basis of this?
card table and write barriers in .net GC
Garbage Collector Basics and Performance Hints
Which object(s) are marked as dirty for the next Gen0/Gen1 mark phases of GC? The entire array instance, or just the new instance of T?
128B block containing the start of the array will be marked as dirty. The newly created instance (new T()) will be a new object, so it will first be checked through a Gen 0 collection without the card table.
For simplicity, presuming that the start of the array is aligned on a 128B boundary, this means the first 128B will be invalidated, so presuming T is a reference type and you're on a 64-bit system, that's first 16 items to check during the next collection.
Will the next Gen0/Gen1 GC mark phase have to go through every item of the array? (That would seem unnecessary and very inefficient.)
Just these 16 to 32 items, depending on the pointer size in this architecture.
Are arrays special in this regard? Would it change the answer if the collection were e.g. a SortedList and I added a new, maximal item?
Arrays are not special. A SortedList<K,T> maintains two arrays internally, so more blocks will end up dirty in the average case.
pretty sure its tracking array slots, not the root which is holding reference to array object itself.
btw if particual card is set dirty, it has to scan 4k of memory. ive read somewhere its now using windows' own mechanism which lets you get notifications if memory range in interest is written to.
I have experience in C and C++(languages without GC) but just recently using C# a lot. I have a question to which I think I got the answer but I want for someone to confirm me, or correct me(if I am wrong).
Say I have the following
int[,] g = new int[nx, ny];
very easy. This just separates memory for a 2D array of ints. After that I can use it, provided that I don't surpass nx or ny as limits of the array.
Now, suppose I want to do this several times but with different nx's and ny's everytime (how this new values are calculated is of no importance)
so I would do
int[,] g;
for(k=0;k<numberOfTimes;k++)
{
//re-calculate nx and ny
g = new int[nx, ny];
//work with g
}
normally I would think that everytime I am separating memory for g, I am leaving leaked memory that could never be reached. Obviously I would have to "delete" this.
But since C# has Garbage Collection, can I do the above with impunity??
In other words, is my code above safe enough?
any suggestion to better it?
Your code is safe enough.
GC collects only those objects on the heap that have no references on the stack pointing to them. As in your scenario, a variable in the for loop scope gets another reference, the previous array loses all available references to it and thus gets collected in some time.
Also, there is no need to declare the variable in the outer scope as it is optimized later on during compile time. More about that : here
When an object is created, a reference is returned, and not the object.
What does this mean?
object a = new object();
Here a holds the reference.
It would be helpful if someone explains the creation of the object, creation of references.
I think of a reference as being like a set of directions to get to a house, where the house represents the object itself.
So if you were to tell someone how to get to your house, you might write down those directions on a piece of paper and give it to them - that's like assigning a reference to a variable.
Coming to your example:
object a = new object();
That's like building a new house (calling the constructor) and then on a piece of paper (the variable a) you write the directions to get to the new house. The paper doesn't have the house itself on it - just directions. If someone copies the contents of the piece of paper, like this:
object b = a;
that doesn't create a second house. It just copies the directions from the piece of paper a to the piece of paper b. Likewise then the two pieces of paper are independent - you could change the value of a to a different set of directions, and it wouldn't change what's on b.
I have an article on this which attempts to explain it another way, which you may find helpful.
The following statement:
object a = new object();
Actually does two different things.
First, new object() allocates the necessary memory to store the instance is allocated on the heap and returns the address on the heap that just got allocated.
Secondly, the assignment is evaluated and assigns the value returned from new to a.
When you say "a holds a reference" it means that a is the memory on the stack (or in registers, or on the heap depending no the lifetime of the reference) that points to the heap location of the instance you just created.
When you instantiate a class with the new keyword you create an object on the heap. It is not referenced by anyone yet. If an object has no references to itself it can be soon garbage collected. To operate with an object you need to reference it. So you create a variable which contains the address of the object(the reference).
With most modern languages you don't have to worry about references vs the object themselves. Back in the day (eg c++) you would have to worry about reference (sometimes called pointers) and even the memory allocated for them. Now the system (and what is called the garbage collector) worries about it for you.
Here is the details. Your example line means the following:
1) allocate memory for object
2) run the constructor
3) put the memory location of that object in the variable "a"
What does the mean to you conceptually as a programmer? Not much, most of the time. In C# you can still think of the variable a as the object. You don't have to worry about it pointing to the object under the hood. Most of the time it does not matter.
Where it matters is when you need to be concerned about the lifetime of the object. Because you have a reference to the object it will not be deallocated which means if it is using a system resource it will continue to do so.
When an object is no longer being referenced it will be deallocated by the garbage collector.
Another tongue-in-cheek analogy for the pile: the object is a helium balloon, and a reference is a string tied to that balloon which you are holding. Saying new object() is equivalent to asking a balloon guy (the memory manager) at the fair (your program) for a new balloon. He may either give you a balloon by means of handing you the string, or he may also tell you that there are no balloons left. You may find the latter very upsetting and run crying from the fair.
You may wish to share the balloon with your sibling, and here the analogy starts to fall apart. This could be seen as both you and your sibling holding onto the same string with your hands, or a second string being tied to the balloon for your sibling. Care must be taken to ensure that those who hold the string(s) tied to the balloon coordinate their movements, otherwise the balloon may be ripped or ruined.
Finally, in a language like C# when you become bored of the balloon, you can simply let go of the string. If others are still holding the string it will not go anywhere, but if they are not it floats harmlessly into a net in the sky, from where the balloon guy periodically collects the released balloons to replenish his stock. In other older languages like C, there is no such net and the balloon guy will never be able to recover the helium in that balloon to make another balloon for someone else. He would really appreciate it if you took the balloon back. This causes other problems: you may return the balloon, but forget that your sibling still wanted it. With their back turned, they don't notice you pulling the string out of their hand and later when they turn and look for it, they will find it is gone and be very upset.
Ridiculous analogy? Yes. Will it stick in your mind? Most likely :)
I looked into the implementation of Array.Resize() and noticed that a new array is created and returned. I'm aiming for zero memory allocation during gameplay and so I need to avoid creating any new reference types. Does resizing an array trigger the Garbage Collector on the previous array? I'm creating my own 2D array resizer, but it essentially functions in the same way as the .NET Resize() method.
If the new array is smaller than the previous one, but excess objects have already been placed back into a generic object pool, will this invoke the GC?
Arrays will constantly be created in my game loop, so I need to try and make it as efficient as possible. I'm trying to create an array pool as such, so that there's no need to keep creating them ingame. However, if the resize method does the same thing, then it makes little sense to not just instantiate a new array instead of having the pool.
Thanks for the help
Array.Resize doesn't actually change the original array at all - anyone who still has a reference to it will be able to use it as before. Therefore there's no optimization possible. Frankly it's a badly named method, IMO :(
From the docs:
This method allocates a new array with
the specified size, copies elements
from the old array to the new one, and
then replaces the old array with the
new one.
So no, it's not going to reuse the original memory or anything like that. It's just creating a shallow copy with a different size.
Yes, using Array.Resize causes a new array to be allocated and the old one to eventually be collected (unless there are still references to it somewhere).
A more low-level array resizer could possibly do some minor optimization in some cases (for example when the array is being made smaller or there happens to be memory available right after the array), but .NET's implementation doesn't do that.
Implicitly yes.
Explicitly no.
Any allocation will eventually be cleaned up by the GC when no more references exist, so yes.
If you want to avoid resizing your arrays, the best thing you could do would be to preallocate with a large enough size to avoid having to reallocate at all. In that case, you might as well just use a collection class with an initial capacity specified in the constructor, such as List.
I have an arraylist of items that only have maybe ten variables in them. But the items have a good bit of code, and I'd like to add more. I'm curious how this will effect the size of my structure. My intuition tells me each one has a stack, but with arguments getting passed around and stuff I've probably not considered I'm unsure. So roughly just how much is code adding to my data structure?
Code does not add to the size of your structure.
The code associated with a class is not usually duplicated per-instance so adding code should not impact the size of your arraylist.
Even though you put code in the same set of curly braces as data, the compiler will separate it out and put it in a different memory section.
That way, you only need one copy of the code - it's not necessary to make a new copy for each item that uses it.
Only in very large projects does the actual size of the compiled code become a problem; usually, it's not much bigger than the source text. On small programs, it's typically a few hundred K or a meg or two at most. It's not worth worrying about on modern machines.
The size of an object instance is (mostly) the sum of its data members. Function members are not stored per-instance, and have no effect on instance size.
Your program has a single stack per thread. When a function is called, stack memory is reserved for each parameter and variable of that function, and freed when it returns.
Your object is stored on the stack if it is instantiated in a function without new. If you use new, only a reference is stored on the stack, and the instance itself is stored on the heap.
:)
Code is not stored on the heap.
Regardless of how many objects you create, you'll only have the code in one place.
The class member functions on which object works are stored differently and it has no effect on size of the object. Where as data members inside the class will be part of the object and object size will change if you change the type of the variable.
ex:
class Test
{
1. member functions
//it does not matter how many functions you have, this section does not contribute
// to object size
2. member variables
//this contributes to the object size, define an int or double etc will change the object size
}
Each object does not have its own stack. Stacks are per thread/process, not per object.