C#/XNA-将对象加载到内存中-它是如何工作的? [英] C# / XNA - Load objects to the memory - how it works?

查看:62
本文介绍了C#/XNA-将对象加载到内存中-它是如何工作的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从C#和XNA开始.在游戏"类的更新"方法中,我有以下代码:

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

加载小图像. 更新"方法就像循环一样工作,因此此代码称为 在一秒钟内很多次.现在,当我运行游戏时,它需要95MB的RAM,然后缓慢地增加到大约130MB(由于我发布的代码,没有此代码,它仍然保持在95MB),然后立即达到了大约100MB(垃圾回收?).然后再缓慢地增加到130MB,然后立即增加到100MB,依此类推.所以我的第一个问题:

  1. 您能解释一下它为什么(如何)工作吗?

我发现,如果我将代码更改为:

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

它的工作原理是:首先需要95MB,然后缓慢地增加到大约101MB(由于 代码),并保持在此级别.

  1. 我不明白为什么要占用这6MB(101-95)...?

  2. 我想使它像这样工作:加载映像,从内存中释放,加载映像,从内存中释放等等,因此该程序应始终占用95MB(当映像仅加载一次时,它将占用95MB)前一种方法).我应该使用什么指示?

如果重要,则图像大小约为10KB.

谢谢!

解决方案

首先,您需要了解您正在做的事情很奇怪!

加载纹理的正常"方法是使用内容管道和内容管理器.

如果您真的必须从文件而不是内容系统中加载纹理-您应该对每个纹理仅执行一次.您应该在Game.LoadContent中使用Texture2D.FromFile,然后在Game.UnloadContent中调用Dispose(通常,内容管理器会为您处理调用Dispose的操作-但由于您没有通过内容管理器,因此必须自己调用Dispose)


要意识到的重要一点是,您在这里同时使用托管和非托管资源.

托管对象使用的内存将由垃圾回收器处理-在这种情况下,Texture2D的每个实例都使用托管内存的 tiny 位. 99%的时间您无需担心-垃圾收集器真的非常擅长处理托管内存-这就是它的工作!

您要做的担心的是非托管资源-在这种情况下,您正在加载的所有这些纹理都使用了纹理内存. 最终垃圾收集器将运行,查看所有这些未引用的Texture2D对象并进行收集.当它收集它们时,它将最终确定它们,就像调用Dispose一样,将释放非托管资源.

但是垃圾收集器无法看到"这些Texture2D对象正在使用的所有非托管资源.它不知道何时需要释放这些对象-您可以自己做得更好.您要做的就是在不再需要纹理时在其纹理上调用Dispose.

这是因为垃圾收集器不知道纹理占用的30MB额外内存,是在不调用Dispose时正在累积的.除此之外,查看进程内存使用情况时看不到的是这些纹理正在使用的GPU上的所有内存!

(Texture2D的基础实现是它持有对DirectX纹理对象的引用-该对象本身是使用非托管主内存的非托管对象-依次处理纹理及其在GPU上的关联内存. Texture2D对象只有大约100-200字节-存储上述引用以及纹理的宽度,高度,格式等的缓存.)


现在-至于您要实现的目标.如果您真的需要在每帧加载纹理(这非常不常见),那么您也将不再需要以前的纹理...

首先,在未使用的纹理上每帧调用Dispose是有效的方法.您将依赖垃圾收集器来清理由此创建的所有垃圾(Texture2D对象的托管端)-在Windows上很好,但可能会削弱Xbox的性能.至少您不会泄漏不受管理的资源.

一个更好的方法,就是每次使用相同的纹理对象时,尤其是在每次纹理都相同的情况下.然后在每个帧上用新的纹理数据调用Texture2D.SetData.

(如果纹理大小不同,或者在给定时间使用多个纹理,则可能需要实现纹理池之类的东西.)

当然,LoadFile接收实际文件,SetData接收原始数据.您必须自己实现数据转换.一个很好的起点可能是 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!

解决方案

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.

这篇关于C#/XNA-将对象加载到内存中-它是如何工作的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆