Sign in to follow this  
Thevenin

struct vs class vs washu

Recommended Posts

I have a class like so:
class ATile
{
     /* C# FTW */
     short TheTile;
     short TheItem;
}
, and I need 67,108,864 of these things instantiated I calculated it should take exactly 256MiB worth of RAM to do this, however, it is actually taking up about 1.4GiB. If I change it to 'struct' data type, than it takes up the correct amount of RAM, but I lose the convenience of passing by reference by default. Inaddition, I've also read that it stores it all in the stack (odd, cause my application didn't crash, and I'm sure my CPU does not have 1.4GiB of stack memory). Is there any way to alleviate the amount of memory consumed, without resorting to declaring it as a struct?

Share this post


Link to post
Share on other sites
Why do you need 67108864 tiles? If it's for a 8192x8192 map it would probably be best to break it up and only load visible and "soon to be visible" parts, possibly using a quad-tree. I don't think there's any really efficent way to load 67108864 tiles, even unmanaged at 256MB would be insane.

Share this post


Link to post
Share on other sites
Quick question...

Define:
struct ATile
{
short TheTile;
}


Than...

ATile TheTile; - ON THE STACK && PASSED BY VALUE
ATile[] TheTile = new ATile[INTEGER_VAL]; - ON THE HEAP && PASSED BY REFERENCE

... right?

Share this post


Link to post
Share on other sites
When using a class the type gets treated as a managed type and so 'ATile' is a reference. When storing an array of these, you're creating an array of N references, N individual objects (assuming you fill out the array), plus the associated book-keeping for each of those objects. You'll also do an incredibly good job of convincing the garbage collector to commit sepuku.

Using a 'struct' for ATile will instead allocate a single contiguous (I think, anyway) block of memory that contains your N ATile's in much the same way as you would expect in a language like C++. The catch though is that if you now try and use ATile in a non-generic collection (ie. it internally stores references of type 'object') each individual instance in that collection will get boxed, adding the extract overhead you would have gotten with using 'class'.

Another thing to keep in mind is that when using 'class' assignment copies the reference (leaving you with 2 references to the same object), but when using 'struct' it copies the contents (leaving you with 2 distinct objects).


BTW, I don't think C# accepts /* C-style comments */ [razz]


Quote:

Is there any way to alleviate the amount of memory consumed, without resorting to declaring it as a struct?


In short, no.

Share this post


Link to post
Share on other sites
Quote:
Original post by joanusdmentia
BTW, I don't think C# accepts /* C-style comments */

Yeah, it does. Everybody loves those - Microsoft could never kill them. [smile]

Share this post


Link to post
Share on other sites
I would really suggest you impliment some landscape pagging. There is no reason you should have to have that many objects in memory at one time. Sure it makes some things a little easier but in the end you will run into more problems then it solves.

v.

Share this post


Link to post
Share on other sites
Quote:
Original post by joanusdmentia
Another thing to keep in mind is that when using 'class' assignment copies the reference (leaving you with 2 references to the same object), but when using 'struct' it copies the contents (leaving you with 2 distinct objects).


I do not believe that it passes arrays of structs by value. I believe the array class is managed; this would explain why it contains the methods and properties associated with arrays.

In otherwords, I believe that passing 'TheTile' will not create two distinct objects.

I still do not know where it creates the memory though.

Share this post


Link to post
Share on other sites
ok the quick answer :-)

it will pass the individual structs by value.
it will pass the array (which may contain structs) by reference.

In conclusion, your both right.

Edit: forgot to answer the were it allocates the memory bit.

Quick answer with examples


struct ATile
{
short something;
short somethingElse;
}

void somefunc()
{
ATile thetile;
ATile[] sometiles = new ATile[100];
}


Ok all of your local variables are created on the stack :-) so thetile is on the stack and the reference to the array (sometiles) is on the stack, but the actual array (all of the ATile's in it) are on the managed heap :-)

hope that helps

Edit: and a quick joke

Are the 67108864 tiles for a 26 dimmention 2x2x2x2x2x2x2x2x2x2x2x2x2x2x2x2x2x2x2x2x2x2x2x2x2x2 array instead of a 8192x8192 array? lol

Share this post


Link to post
Share on other sites
Wait, so you started with a class, tested and solved your problem by using a struct - but want to go back to using a class? Because you don't like the additional syntax for passing things by reference for a value type?

The structure you posted appears to be just plain old data, and simple data at that - that's exactly the situation the framework guys had in mind for when people should use struct over class.

The memory management in .Net is black box, and we're told a few heuristics that can make the garbage collectors job easier. Value types are a lot easier for the GC to deal with because in general they have very short lifespans - or their life span is directly linked to the class object they are declared in. It doesn't have to chase around references to figure out if it's in use or not.

The garbage collector is very lazy, it only collects when there is a compelling need to do so - and even then it always tries to get away with as little as it can.

Gamefest had some awesome presentations on memory management if you have time and bandwidth def look it up.

I don't know, coming from a C++ background myself, complaining over having to use ref is a bit like complaining about & in c++. It's not really that bad, is it?

I'm also unsure about how many places you actually would want to let something mess around with your tile array directly?

Share this post


Link to post
Share on other sites
Quote:
Original post by paulecoyote
Wait, so you started with a class, tested and solved your problem by using a struct - but want to go back to using a class? Because you don't like the additional syntax for passing things by reference for a value type?


This thread is actually solving two problems, so I imagine it is quite confusing to anyone reading it. I'll explain in detail what I'm doing.

My MMORPG has a server/client model. The server loads up the (now) 2048x2048x4* array of AServerTile. And the client loads up the (now) 2048x2048x4 array of AClientTile.

AServerTile is a class with two shorts. AClientTile is a class with one short.

This works out fine except, alot of RAM is being consumed due to the extra bytes appended on each tile due to usage of a 'class' instead of a 'struct'.

The server benefits greatly from using a class, because I do alot of simplification code that takes advantage of the 'pass by reference' properties of classes. And so, I don't care too much anymore that it takes up almost four times the amount of ram that it would normally use.

The client, however, can't take up huge quantities of RAM because that would knock up the system requirements for my game. However, the client doesn't do anything particularly complicated with the tiles, so it could very well use 'structs' instead.

And so, what I'm going to do now is recode my client to have <t>AClientTile defined as a 'struct' instead of a 'class'.

... and btw, I have a background in procedural-c (aswell as basic, actionscript, and java); I don't know why this is of important relevence, but since others are posting their backgrounds [rolleyes].

Share this post


Link to post
Share on other sites
Appoligies if you took offence to something I said, err I guess the "importance" was that I was trying to put in to context why I thought using "&" or "ref" to mark out passing by reference didn't seem that bad to me, that's all [wink]. Personally I think the parameter passing in Pascal and Ada is great, but that's probably quite a personal taste!

The extra info you provided puts a better context on things, but it doesn't change that the GC is going to have a tough time clearing up that many class instances over that many struct instances.

Out of interest you run your code through CLR Profiler or similar - or are you just watching task manager for the memory usage?

Share this post


Link to post
Share on other sites
This is about Java, but it's relevant. Basically (to the best of my understanding), C# uses the Java object model for classes, and the C++ one for structs (which is why the whole auto-pass-by-reference thing works the way it does; it doesn't really pass by reference, it passes *a* reference by value).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this