简体   繁体   English

您如何在 Android 上的 OpenGLES 中有效地管理纹理内存?

[英]How do you efficiently manage texture memory in OpenGLES on Android?

I am loading textures into OpenGLES on Android and maintaining a reference to the generated id in a HashMap.我正在将纹理加载到 Android 上的 OpenGLES 中,并在 HashMap 中维护对生成的id的引用。

At a given point in time not all textures that have been loaded will be in use, but may be used at a later point in time, therefore if the device has enough free memory I'd like to keep the textures loaded.在给定的时间点,并非所有已加载的纹理都将被使用,但可能会在稍后的时间点使用,因此如果设备有足够的可用内存,我希望保持纹理加载。

However, if the device starts running low on memory I would like to delete any textures that are not in use since they can always be reloaded later if they're required.但是,如果设备开始内存不足,我想删除任何未使用的纹理,因为如果需要,它们总是可以在以后重新加载。

I've tried a few methodologies for handling this scenario.我已经尝试了几种方法来处理这种情况。

1. Respond to system memory warnings 1.响应系统内存警告

If the application receives a memory warning, then it will identify which textures are not in use and schedule for those textures to be deleted.如果应用程序收到内存警告,则它将识别哪些纹理未在使用中并计划删除这些纹理。

This method did work reasonably well.这种方法确实工作得相当好。

2. Use Soft References 2.使用软引用

In this approach the application would maintain a List<SoftReference<Texture>> where the Texture class is a wrapper around the id that was returned when a given texture was loaded into OpenGLES.在这种方法中,应用程序将维护一个List<SoftReference<Texture>> ,其中Texture类是在将给定纹理加载到 OpenGLES 中时返回的id的包装器。

If a given Texture is not in use at a given point in time then only a SoftReference would exist to this Texture and thus if the garbage collector deemed it necessary it could reclaim this memory and the finalize method on the Texture class would schedule for this texture to be deleted.如果一个给定的Texture在给定的时间点没有被使用,那么这个Texture将只存在一个SoftReference ,因此如果垃圾收集器认为有必要,它可以回收这个内存,并且Texture类上的finalize方法将为这个纹理调度被删除。

This approach seemed ideal based upon the description of SoftReference in the Java documentation , since they would only be reclaimed when more memory was required.根据Java 文档中对SoftReference的描述,这种方法似乎是理想的,因为只有在需要更多内存时才会回收它们。

Soft reference objects, which are cleared at the discretion of the garbage collector in response to memory demand.软引用对象,由垃圾收集器根据内存需求自行清除。 Soft references are most often used to implement memory-sensitive caches.软引用最常用于实现对内存敏感的缓存。

However, the Android implementation of SoftReference does not work like this: since Android 9 as the garbage collector is more aggressive and the soft references are reclaimed almost immediately regardless of whether the device is low on memory.然而, SoftReference的 Android 实现并不是这样工作的:因为作为垃圾收集器的 Android 9 更加积极,无论设备内存是否不足,软引用几乎都会立即被回收。

3. Use LruCache 3.使用LruCache

The Android documentation advises against using SoftReference in a cache implementation and to use a LruCache instead. Android 文档建议不要在缓存实现中使用SoftReference ,而是使用LruCache However, the LruCache poses some drawbacks.然而, LruCache有一些缺点。

Firstly, you have to specifying the maximum size of the cache.首先,您必须指定缓存的最大大小。 It isn't obvious what to set the cache size to: ideally it'd just automatically be set as high as possible while still being a good citizen.将缓存大小设置为什么并不明显:理想情况下,它会自动设置得尽可能高,同时仍然是一个好公民。 If it's set too small, it might be constantly reloading textures unnecessarily.如果它设置得太小,它可能会不断地重新加载不必要的纹理。

Secondly, a Texture may be removed from the cache which is currently in use and thus may be deleted from OpenGLES and then display as a missing texture to the user.其次, Texture可能会从当前正在使用的缓存中删除,因此可能会从 OpenGLES 中删除,然后作为丢失的纹理显示给用户。

Is there a better way to maintain a cache of textures in OpenGL and be responsive to low memory scenarios (besides just deleting textures upon memory warnings)?有没有更好的方法来维护 OpenGL 中的纹理缓存并响应低内存场景(除了在内存警告时删除纹理之外)?

Talking about best practices, large caches (that can take all the memory) with OpenGL ids for textures are rarely used.谈到最佳实践,很少使用带有 OpenGL 纹理 ID 的大型缓存(可以占用所有内存)。 Actually it's worth to have only a few textures to render in the scene at one moment.实际上,在某一时刻只在场景中渲染几个纹理是值得的。 More textures you have in the scene, more texture switches you need to do in frame.场景中的纹理越多,帧中需要进行的纹理切换就越多。 It costs.它的成本。 Texture atlases were developed many years ago to reduce number of texture switches.许多年前开发了纹理图集以减少纹理切换的数量。 However, atlases still can take a lot of memory.但是,地图集仍然会占用大量内存。

With development of hardware capabilities and user expectations, texture atlases evolved into virtual/mega/sparse textures + texture data streaming for the cases of high memory usage.随着硬件能力和用户期望的发展,纹理图集演变为虚拟/巨型/稀疏纹理+用于高内存使用情况的纹理数据流。 The idea is to use virtual memory approach and load/unload blocks of one very large texture in real-time.这个想法是使用虚拟内存方法并实时加载/卸载一个非常大的纹理块。 It has some drawbacks, good discussion about it can be found here .它有一些缺点,关于它的很好的讨论可以在这里找到。 LRU cache can be built on top of it to tell what blocks are required at the moment. LRU 缓存可以建立在它之上,以告诉当前需要哪些块。

Of course, engines can preload many textures (sparse or usual ones) and unload it after usage, eg as a part of dynamic loading of open world in a game.当然,引擎可以预加载许多纹理(稀疏的或普通的)并在使用后卸载它,例如作为游戏中开放世界动态加载的一部分。 These textures aren't used for rendering simultaneously, and no one waits until they take all the memory to start unloading.这些纹理不会同时用于渲染,也没有人会等到它们占用所有内存后才开始卸载。 The eviction algorithm here is highly dependant on particular app, even though maximum cache size in Mb is widely used practice here.这里的逐出算法高度依赖于特定的应用程序,即使以 Mb 为单位的最大缓存大小在这里被广泛使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM