質問編集履歴

2 修正

gotchcuru

gotchcuru score 27

2016/06/15 15:35  投稿

メモリリークの原因を教えてください
http://www.mdn.co.jp/di/book/3214303003/?page=2
上の本に書かれていたtipsをもとに、以下のようにコードを記述したのですが、
メモリリークが発生してしまい、原因と修正方法がわからないのでお教え頂きたいです。
コードの内容としては複数枚の静止画をつなぎ合わせ動画ファイルに変換しています。
漠然とした質問でも申し訳ありませんが、何卒よろしくおねがいします。。。
```swift
#import "MovieCreator.h"
@implementation MovieCreator
/*!
画像の配列から動画を生成する。
@param images 画像の配列
@param path 動画ファイルの出力先
*/
- (void)writeImagesAsMovie:(NSArray *)images toPath:(NSString *)path
{
NSFileManager *fileManager = [NSFileManager defaultManager];
// ファイルを削除する
[fileManager removeItemAtPath:path error:nil];
// 最初の画像から動画のサイズ指定する
CGSize size = ((UIImage *)images[0]).size;
_videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:path]
fileType:AVFileTypeQuickTimeMovie
error:nil];
NSDictionary *outputSettings =
@{
AVVideoCodecKey : AVVideoCodecH264,
AVVideoWidthKey : @(size.width),
AVVideoHeightKey : @(size.height),
};
AVAssetWriterInput *writerInput = [AVAssetWriterInput
assetWriterInputWithMediaType:AVMediaTypeVideo
outputSettings:outputSettings];
[_videoWriter addInput:writerInput];
AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor
assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput
sourcePixelBufferAttributes:nil];
[_videoWriter startWriting];
[_videoWriter startSessionAtSourceTime:kCMTimeZero];
CVPixelBufferRef buffer = NULL;
int frameCount = 0;
// 次の画像を表示する時間感覚の設定です。
// この数字を小さくすると、早く画像が変わるので滑らかに動きます。
// この数字を大きくすると、かくかくした動画になり、面白いです。
float durationForEachImage = 0.5;
int32_t fps = 24;
for (UIImage *image in images)
{
if (adaptor.assetWriterInput.readyForMoreMediaData)
{
CMTime frameTime = CMTimeMake((int64_t)frameCount * fps * durationForEachImage, fps);
buffer = [self pixelBufferFromCGImage:image.CGImage];
if (![adaptor appendPixelBuffer:buffer withPresentationTime:frameTime])
{
NSLog(@"Failed to append buffer. [image : %@]", image);
}
if(buffer) {
CVBufferRelease(buffer);
}
frameCount++;
[NSThread sleepForTimeInterval:0.05];
}
else
{
[NSThread sleepForTimeInterval:0.1];
}
}
// 動画生成終了
[writerInput markAsFinished];
[_videoWriter finishWritingWithCompletionHandler:^
{
NSLog(@"Finish writing!");
// 動画をカメラロールに保存する
UISaveVideoAtPathToSavedPhotosAlbum(path, self, nil, nil);
}];
CVPixelBufferPoolRelease(adaptor.pixelBufferPool);
}
- (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image
{
CVPixelBufferRef pxbuffer = NULL;
CVPixelBufferCreate(kCFAllocatorDefault,
CGImageGetWidth(image),
CGImageGetHeight(image),
kCVPixelFormatType_32ARGB,
NULL,
&pxbuffer);
CVPixelBufferLockBaseAddress(pxbuffer, 0);
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pxdata,
CGImageGetWidth(image),
CGImageGetHeight(image),
8,
4 * CGImageGetWidth(image),
colorspace,
(CGBitmapInfo)kCGImageAlphaNoneSkipFirst);
CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
CGContextRelease(context);
CGColorSpaceRelease(colorspace);
return pxbuffer;
}
@end
```
メモリの増加を追ってみると、以下の箇所でメモリが急上昇しております。
```Swift
int frameCount = 0;
// 次の画像を表示する時間感覚の設定です。
// この数字を小さくすると、早く画像が変わるので滑らかに動きます。
// この数字を大きくすると、かくかくした動画になり、面白いです。
float durationForEachImage = 0.5;
int32_t fps = 24;
for (UIImage *image in images)
{
if (adaptor.assetWriterInput.readyForMoreMediaData)
{
CMTime frameTime = CMTimeMake((int64_t)frameCount * fps * durationForEachImage, fps);
buffer = [self pixelBufferFromCGImage:image.CGImage];
if (![adaptor appendPixelBuffer:buffer withPresentationTime:frameTime])
{
NSLog(@"Failed to append buffer. [image : %@]", image);
}
if(buffer) {
CVBufferRelease(buffer);
}
frameCount++;
[NSThread sleepForTimeInterval:0.05];
}
else
{
[NSThread sleepForTimeInterval:0.1];
}
}
```
![イメージ説明](863e7a35bbbd70905431269b4259937b.png)
  • Swift 2

    1350 questions

    Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

  • Swift

    11320 questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • Objective-C

    1336 questions

    Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

1 追記

gotchcuru

gotchcuru score 27

2016/06/15 15:18  投稿

メモリリークの原因を教えてください
http://www.mdn.co.jp/di/book/3214303003/?page=2
上の本に書かれていたtipsをもとに以下のようにコードを記述したのですが、
上の本に書かれていたtipsをもとに、以下のようにコードを記述したのですが、
メモリリークが発生してしまい、原因と修正方法がわからないのでお教え頂きたいです。
 
コードの内容としては複数枚の静止画をつなぎ合わせ動画ファイルに変換しています。  
漠然とした質問でも申し訳ありませんが、何卒よろしくおねがいします。。。
```swift
#import "MovieCreator.h"
@implementation MovieCreator
/*!
画像の配列から動画を生成する。
@param images 画像の配列
@param path 動画ファイルの出力先
*/
- (void)writeImagesAsMovie:(NSArray *)images toPath:(NSString *)path
{
   NSFileManager *fileManager = [NSFileManager defaultManager];
   
   // ファイルを削除する
   [fileManager removeItemAtPath:path error:nil];
   
   // 最初の画像から動画のサイズ指定する
   CGSize size = ((UIImage *)images[0]).size;
   
   _videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:path]
                                            fileType:AVFileTypeQuickTimeMovie
                                               error:nil];
   
   NSDictionary *outputSettings =
   @{
     AVVideoCodecKey : AVVideoCodecH264,
     AVVideoWidthKey : @(size.width),
     AVVideoHeightKey : @(size.height),
     };
   
   AVAssetWriterInput *writerInput = [AVAssetWriterInput
                                      assetWriterInputWithMediaType:AVMediaTypeVideo
                                      outputSettings:outputSettings];
   
   [_videoWriter addInput:writerInput];
   
   AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor
                                                    assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput
                                                    sourcePixelBufferAttributes:nil];
   
   [_videoWriter startWriting];
   
   [_videoWriter startSessionAtSourceTime:kCMTimeZero];
   
   CVPixelBufferRef buffer = NULL;
   
   int frameCount = 0;
   // 次の画像を表示する時間感覚の設定です。
   // この数字を小さくすると、早く画像が変わるので滑らかに動きます。
   // この数字を大きくすると、かくかくした動画になり、面白いです。
   float durationForEachImage = 0.5;
   int32_t fps = 24;
   
   for (UIImage *image in images)
   {
       if (adaptor.assetWriterInput.readyForMoreMediaData)
       {
           CMTime frameTime = CMTimeMake((int64_t)frameCount * fps * durationForEachImage, fps);
           
           buffer = [self pixelBufferFromCGImage:image.CGImage];
           
           if (![adaptor appendPixelBuffer:buffer withPresentationTime:frameTime])
           {
               NSLog(@"Failed to append buffer. [image : %@]", image);
           }
           
           if(buffer) {
               CVBufferRelease(buffer);
           }
           
           frameCount++;
           
           [NSThread sleepForTimeInterval:0.05];
       }
       else
       {
           [NSThread sleepForTimeInterval:0.1];
       }
   }
   
   // 動画生成終了
   [writerInput markAsFinished];
   [_videoWriter finishWritingWithCompletionHandler:^
    {
        NSLog(@"Finish writing!");
       
        // 動画をカメラロールに保存する
        UISaveVideoAtPathToSavedPhotosAlbum(path, self, nil, nil);
       
    }];
   CVPixelBufferPoolRelease(adaptor.pixelBufferPool);
}
- (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image
{
   CVPixelBufferRef pxbuffer = NULL;
   
   CVPixelBufferCreate(kCFAllocatorDefault,
                       CGImageGetWidth(image),
                       CGImageGetHeight(image),
                       kCVPixelFormatType_32ARGB,
                       NULL,
                       &pxbuffer);
   
   CVPixelBufferLockBaseAddress(pxbuffer, 0);
   void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
   
   CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
   
   CGContextRef context = CGBitmapContextCreate(pxdata,
                                                CGImageGetWidth(image),
                                                CGImageGetHeight(image),
                                                8,
                                                4 * CGImageGetWidth(image),
                                                colorspace,
                                                (CGBitmapInfo)kCGImageAlphaNoneSkipFirst);
   
   CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
   
   CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
   
   CGContextRelease(context);
   CGColorSpaceRelease(colorspace);
   
   return pxbuffer;
}
@end
```
メモリの増加を追ってみると、以下の箇所でメモリが急上昇しております。
```Swift
int frameCount = 0;
   // 次の画像を表示する時間感覚の設定です。
   // この数字を小さくすると、早く画像が変わるので滑らかに動きます。
   // この数字を大きくすると、かくかくした動画になり、面白いです。
   float durationForEachImage = 0.5;
   int32_t fps = 24;
   for (UIImage *image in images)
   {
       if (adaptor.assetWriterInput.readyForMoreMediaData)
       {
           CMTime frameTime = CMTimeMake((int64_t)frameCount * fps * durationForEachImage, fps);
           buffer = [self pixelBufferFromCGImage:image.CGImage];
           if (![adaptor appendPixelBuffer:buffer withPresentationTime:frameTime])
           {
               NSLog(@"Failed to append buffer. [image : %@]", image);
           }
           if(buffer) {
               CVBufferRelease(buffer);
           }
           frameCount++;
           [NSThread sleepForTimeInterval:0.05];
       }
       else
       {
           [NSThread sleepForTimeInterval:0.1];
       }
   }
```
![イメージ説明](863e7a35bbbd70905431269b4259937b.png)
![イメージ説明](863e7a35bbbd70905431269b4259937b.png)
  • Swift

    11320 questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • Swift 2

    1350 questions

    Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る