直接的な答えではありませんが、私が気付いたことがあり、コメントにはあまり当てはまりません。
バックグラウンドでテクスチャをロードして既存のテクスチャを置き換えるために使用している場合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;
});
}];