Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# / XNA - Load objects to the memory - how it works?

Tags:

c#

memory

xna

I'm starting with C# and XNA. In the "Update" method of the "Game" class I have this code:

t = Texture2D.FromFile( [...] ); //t is a 'Texture2D t;'

which loads small image. "Update" method is working like a loop, so this code is called many times in a second. Now, when I run my game, it takes 95MB of RAM and it goes slowly to about 130MB (due to the code I've posted, without this code it remains at 95MB), then goes immediately to about 100MB (garbare colletion?) and again goes slowly to 130MB, then immediately to 100MB and so on. So my first question:

  1. Can You explain why (how) it works like that?

I've found, that if I change the code to:

t.Dispose()
t = Texture2D.FromFile( [...] );

it works like that: first it takes 95MB and then goes slowly to about 101MB (due to the code) and remains at this level.

  1. I don't understand why it takes this 6MB (101-95)... ?

  2. I want to make it works like that: load image, release from memory, load image, release from memory and so on, so the program should always takes 95MB (it takes 95MB when image is loaded only once in previous method). Whats instructions should I use?

If it is important, the size of the image is about 10KB.

Thank You!

like image 531
carl Avatar asked Jun 16 '10 01:06

carl


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr. Stroustroupe.

Is C programming hard?

C is more difficult to learn than JavaScript, but it's a valuable skill to have because most programming languages are actually implemented in C. This is because C is a “machine-level” language. So learning it will teach you how a computer works and will actually make learning new languages in the future easier.


2 Answers

First of all you need to understand that what you are doing is pretty strange!

The "normal" way to load a texture is to use the content pipeline and the content manager.

If you really have to load a texture from file and not the content system - you should do this only once for each texture. You should use Texture2D.FromFile in Game.LoadContent, and call Dispose in Game.UnloadContent (normally the content manager would handle calling Dispose for you - but because you're not going through the content manager you have to call Dispose yourself).


The important thing to realise is that you're working with both managed and unmanaged resources here.

The memory being used by managed objects will be handled by the garbage collector - in this case each instance of Texture2D uses a tiny bit of managed memory. 99% of the time you don't need to worry about it - the garbage collector is really good at handling managed memory - that's its job!

What you do need to worry about is the unmanaged resources - in this case the texture memory being used by all these textures you're loading. Eventually the garbage collector will run, see all these unreferenced Texture2D objects and collect them. When it collects them it will finalize them which, like calling Dispose, will release the unmanaged resources.

But the garbage collector cannot "see" all the unmanaged resources these Texture2D objects are using. It doesn't know when those objects need to be released - you can do a much better job yourself. All you have to do is call Dispose on your textures when they are no longer needed.

It's because the garbage collector doesn't know about that 30MB of extra memory used by your textures, that it is being accumulated when you are not calling Dispose. In addition to that, what you cannot see when you look at the process memory usage, is all the memory on the GPU that those textures are using!

(The underlying implementation of Texture2D is that it holds a reference to a DirectX texture object - which itself is an unmanaged object using unmanaged main memory - which in turn handles the texture and its associated memory on the GPU. The managed part of a Texture2D object is only about 100-200 bytes - which stores the aforementioned reference and a cache of the texture's width, height, format and so on.)


Now - as for what you are trying to achieve. If you really have a need to load a texture every frame (this is highly unusual), and you then also no longer need the previous texture...

Well, first of all, calling Dispose on the unused texture each frame is a valid method. You will be depending on the garbage collector to clean up all the garbage this creates (the managed side of Texture2D objects) - this is fine on Windows but might kill your performance on Xbox. At least you won't be leaking unmanaged resources.

A better method, particularly if the texture is the same size each time, is to just keep using the same texture object. Then call Texture2D.SetData on it with the new texture data each frame.

(If your textures are different sizes, or you have more than one in use at a given time, you might need to implement something like a texture pool.)

Of course, LoadFile takes an actual file, SetData takes raw data. You'll have to implement the data conversion yourself. A good starting point might be this thread on the XNA forum.

like image 74
Andrew Russell Avatar answered Oct 06 '22 14:10

Andrew Russell


The Update Method should not be used to load Textures because it's loaded a lot. In .net, objects are garbage collected, which means that you can't explicitly free an object (even .Dispose doesn't do that).

If the system is under a lot of pressure, GC may not run as often as it could.

In short: You are "leaking" thousands of Texture2Ds.

The proper way to load them is in one of the Initialization Events and store them in a class variable, Dictionary, List or whatever structure. Basically, load it only once and then reuse it.

If you have to load a texture on-demand, only load it once and store it in the List/Dictionary/Class Variable and again reuse it.

Edit: Your approach of "Load Image, Release, Load, Release" won't work in .net, simply because you can't explicitly free memory. You could call GC.Collect, but that a) doesn't guaratee it either and b) GC.Collect is incredibly slow.

Is there a specific reason why you have to reload the image 60 times a second? If you only need to reload it every second or so, then you can use elapsedGameTime to measure the time expired since the last .Update and if it's more than your threshold, Reload the image. (You need a Class Variable like "LastUpdated" against which you compare and which you update when you reload the image)

like image 20
Michael Stum Avatar answered Oct 06 '22 13:10

Michael Stum