天天看點

iOS性能優化-記憶體優化

https://blog.csdn.net/a184251289/article/details/82589128

2018年09月10日 14:25:31 xingshao1990 閱讀數:328

 版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。 https://blog.csdn.net/a184251289/article/details/82589128

  • 一、為什麼需要記憶體優化
  • 二、記憶體管理
  • 三、常見問題
  • 四、記憶體占用
  • 五、檢測工具
  • 摘要

一、為什麼需要記憶體優化

The easy answer is users have a better experience. 

Not only will your app launch faster. 

The system will perform better. 

Your app will stay in memory longer. 

Other apps will stay in memory longer. 

Pretty much everything’s better.

二、記憶體管理

Objective-C語言本身是支援垃圾回收機制的,但有平台局限性,僅限于Mac桌面系統開發中,而在iPhone和iPad等蘋果移動終端裝置中是不支援垃圾回收機制的。在移動裝置開發中的記憶體管理是采用MRC(Manual Reference Counting)以及iOS5以後的ARC(Automatic Reference Counting),本質都是RC引用計數,通過引用計數的方式來管理記憶體的配置設定與釋放,進而防止記憶體洩漏。

記憶體洩漏(Memory Leak)是指程式中己動态配置設定的堆記憶體由于某種原因程式未釋放或無法釋放,造成系統記憶體的浪費,導緻程式運作速度減慢甚至系統崩潰等嚴重後果。

三、常見問題

記憶體問題主要包括兩個部分,一個是iOS中常見循環引用導緻的記憶體洩露 ,另外就是大量資料加載及使用導緻的記憶體警告。

1、mmap 

雖然蘋果并沒有明确每個App在運作期間可以使用的記憶體最大值,但是有開發者進行了實驗和統計,一般在占用系統記憶體超過20%的時候會有記憶體警告,而超過50%的時候,就很容易Crash了,是以記憶體使用率還是盡量要少,對于資料量比較大的應用,可以采用分步加載資料的方式,或者采用mmap方式。mmap 是使用邏輯記憶體對磁盤檔案進行映射,中間隻是進行映射沒有任何拷貝操作,避免了寫檔案的資料拷貝。 操作記憶體就相當于在操作檔案,避免了核心空間和使用者空間的頻繁切換。之前在開發輸入法的時候 ,詞庫的加載也是使用mmap方式,可以有效降低App的記憶體占用率。

1>Cell的重用機制,包括UITableView、UICollectionView。

2、循環引用 

循環引用是iOS開發中經常遇到的問題,尤其對于新手來說是個頭疼的問題。循環引用對App有潛在的危害,會使記憶體消耗過高,性能變差和Crash等,iOS常見的記憶體主要以下三種情況:

1>Delegate 

代理聲明為weak是一個即好又安全的做法 

@property (nonatomic, weak) id <MyCustomDelegate> delegate;

2>NSTimer 

使用類方法 

使用weakProxy 

使用GCD timer

3>Block

3、其他 

1>NSNotification addObserver之後,在dealloc裡面添加remove。 

2>動畫的repeat count無限大,而且也不主動停止動畫,基本就等于無限循環。 

3>forwardingTargetForSelector不能傳回self。 

4>UIGraphicsBeginImageContext之後調用UIGraphicsEndImageContext。 

5>C文法,malloc之後調用free。 

6>CoreFoundation 

7>明确标注需要release的函數。 

SecPKCS12Import、protocol_copyMethodDescriptionList等

四、記憶體占用

五、檢測工具

1、Xcode Memory Debugger 

2、Instruments 

3、FBRetainCycleDetector 

FBAlloca1onTracker 

FBMemoryProfiler 

4、MLeaksFinder

摘要

https://developer.apple.com/videos/play/wwdc2018/416/ 

https://juejin.im/post/5b23dafee51d4558e03cbf4f 

https://blog.csdn.net/cordova/article/details/60958978 

https://juejin.im/post/58ca0832a22b9d006418fe43

iOS最全圖檔記憶體優化

https://blog.csdn.net/weixin_33674437/article/details/88181214

2018年07月30日 14:04:00 weixin_33674437 閱讀數:25

在加載大量圖檔的時候,尤其是一些高清大圖的時候如果不做什麼處理,很容易導緻APP記憶體溢出,軟體閃退的問題。

在加載圖檔的時候,我們一般使用SDWebimage架構,是以,下面的處理方法,我們也是以SDWebimage架構來處理。

清理緩存

最簡單的一個操作就是監聽tableView的滾動事件,當進行了滾動的時候進行緩存的清理來減少記憶體。

[[SDWebImageManager sharedManager].imageCache clearMemory];

[[SDImageCache sharedImageCache] setValue:nil forKey:@"memCache"];//建議使用這句話,效果更好

更改圖檔加載方式

我們一般加載本地圖檔的時候都是使用圖檔的名稱來加載圖檔,但是這種加載方式會先把圖檔加載到記憶體中,是以如果圖檔很大的話,就會影響到記憶體,是以,建議使用NSData的方法來加載圖檔。

[UIImage imageNamed:ImageName];

//更換為

NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:extension];

NSData *image = [NSData dataWithContentsOfFile:filePath];

[UIImage imageWithData:image];

進行緩存清理

監聽scrollView的滾動事件,一旦滾動就清理緩存

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{

    [[SDImageCache sharedImageCache] setValue:nil forKey:@"memCache"];

}

監聽記憶體警告,一旦收到記憶體警告就清理緩存

- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    [[SDImageCache sharedImageCache] setValue:nil forKey:@"memCache"];

}

減少圖檔體積

記憶體溢出的主要原因是因為圖檔體積過大,是以,我們可以減少圖檔的體積來達到減少記憶體的溢出

方法一:

把圖檔轉為jpg格式,并且壓縮圖檔像素,會導緻圖檔模糊,CPU使用上升,但是記憶體會下降。

NSData *imageData = UIImageJPEGRepresentation(image, 0.5);//取值範圍0~1

UIImage *ipgImage = [UIImage imageWithData:imageData];

方法二:

在SDWebimage中修改下載下傳的圖檔體積,SDWebimageManager.m檔案中添加如下代碼,會導緻圖檔模糊,CPU使用上升,但是記憶體會下降。

-(UIImage *)compressImageWith:(UIImage *)image

{

    float imageWidth = image.size.width;

    float imageHeight = image.size.height;

    CGSize croppedSize;

    CGFloat offsetX = 0.0;

    CGFloat offsetY = 0.0;

    if (imageWidth > imageHeight) {

        offsetX = (imageWidth -imageHeight) / 2;

        croppedSize = CGSizeMake(imageHeight, imageHeight);

    } else {

        offsetY = (imageHeight-imageWidth) / 2;

        croppedSize = CGSizeMake(imageWidth, imageWidth);

    }

    CGRect clippedRect = CGRectMake(offsetX, offsetY, croppedSize.width, croppedSize.height);

    CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], clippedRect);

    float ratio = croppedSize.width>120?120:croppedSize.width;

    CGRect rect = CGRectMake(0.0, 0.0, ratio, ratio);

    UIGraphicsBeginImageContext(rect.size);

    [[UIImage imageWithCGImage:imageRef] drawInRect:rect];

    UIImage *thumbnail = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    CGImageRelease(imageRef);

    return thumbnail;

}

然後我們要讓圖檔來進行這個減少送出操作

//在擷取到記憶體中的圖檔進行體積減少操作

else if (cachedImage) {

    cachedImage = [self compressImageWith:cachedImage];//修改圖檔大小

    [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url];

    [self safelyRemoveOperationFromRunning:strongOperation];

} else {

//在下載下傳完成後對圖檔進行體積減少操作

if (downloadedImage && finished) {//修改圖檔大小

      [self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key toDisk:cacheOnDisk completion:nil];

    downloadedImage = [self compressImageWith:downloadedImage];

    downloadedData = [NSMutableData dataWithData:UIImageJPEGRepresentation(downloadedImage, 1)];

//                            if (self.cacheSerializer) {

//                                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

//                                    NSData *cacheData = self.cacheSerializer(downloadedImage, downloadedData, url);

//                                    [self.imageCache storeImage:downloadedImage imageData:cacheData forKey:key toDisk:cacheOnDisk completion:nil];

//                                });

//                            } else {

//                                [self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key toDisk:cacheOnDisk completion:nil];

//                            }

}

[self callCompletionBlockForOperation:strongSubOperation completion:completedBlock image:downloadedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url];

--------------------- 

作者:weixin_33674437 

來源:CSDN 

原文:https://blog.csdn.net/weixin_33674437/article/details/88181214 

版權聲明:本文為部落客原創文章,轉載請附上博文連結!