struct vs class vs washu

Started by
10 comments, last by Zahlman 17 years, 5 months ago
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?
Advertisement
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.
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?

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.
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
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]
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.
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.
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
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?
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
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].

This topic is closed to new replies.

Advertisement