不是一个直接的答案,但我注意到,它不会真正适合评论。
如果您使用GLKTextureLoader
在背景中加载纹理以替换现有纹理,则必须删除主线程上的现有纹理。在完成处理程序中删除纹理将不起作用。
据我所知,这是因为:
- 每部iOS线程都需要有自己的EAGLContext,所以背景队列都有自己的线程有自己的上下文。
- 完成处理程序在您传入的队列上运行,这很可能不是主队列。 (否则你不会做的装载在后台...)
也就是说,这将导致内存泄漏。
NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft:@YES};
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
[self.asyncTextureLoader textureWithContentsOfFile:@"my_texture_path.png"
options:options
queue:queue
completionHandler:^(GLKTextureInfo *texture, NSError *e){
GLuint name = self.myTexture.name;
//
// This delete textures call has no effect!!!
//
glDeleteTextures(1, &name);
self.myTexture = texture;
}];
为了解决这个问题,您可以:
- 删除纹理上传发生之前。根据您的GL架构如何,可能略有不同。
- 删除完成处理程序中主队列上的纹理。
因此,要修复泄漏,你需要这样做:
//
// Method #1, delete before upload happens.
// Executed on the main thread so it works as expected.
// Potentially leaves some GL content untextured if you're still drawing it
// while the texture is being loaded in.
//
// Done on the main thread so it works as expected
GLuint name = self.myTexture.name;
glDeleteTextures(1, &name)
NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft:@YES};
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
[self.asyncTextureLoader textureWithContentsOfFile:@"my_texture_path.png"
options:options
queue:queue
completionHandler:^(GLKTextureInfo *texture, NSError *e){
// no delete required, done previously.
self.myTexture = texture;
}];
或
//
// Method #2, delete in completion handler but do it on the main thread.
//
NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft:@YES};
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
[self.asyncTextureLoader textureWithContentsOfFile:@"my_texture_path.png"
options:options
queue:queue
completionHandler:^(GLKTextureInfo *texture, NSError *e){
// you could potentially do non-gl related work here, still in the background
// ...
// Force the actual texture delete and re-assignment to happen on the main thread.
dispatch_sync(dispatch_get_main_queue(), ^{
GLuint name = self.myTexture.name;
glDeleteTextures(1, &name);
self.myTexture = texture;
});
}];
嗯。到目前为止没有回应,所以这是正式的,因为它现在对我来说是正式的。 :-)我的想法是'GLKTextureInfo'会管理这个(即释放它在解除分配时指向的纹理的句柄),但显然情况并非如此。 – alokoko 2012-01-14 20:20:54
我相信这是做到这一点的正确方法。问题是,在将纹理绑定到GL之后创建textureInfo后,GL将拥有内存,因此您需要使用GL来删除内存 – 2012-02-21 19:36:15
Anthoys的解释对我来说很有意义。 +1。 – Soup 2012-09-10 10:02:47