メモリのIOSのパフォーマンスの最適化(メモリ)の最適化

https://www.jianshu.com/p/8662b2efbb23

 

最近の研究では、APPのメモリフットプリントは、メモリフットプリントの数を低減するように最適化された、これは、我々はまた、通信に歓迎し、経験とシェアを合計します。

最適化の過程で、以下のツールの主な用途:

  • 楽器との割り当ては、
    このツールは、実際のメモリフットプリントのアプリケーションを表示することができ、サイズによってソートすることができます。限り、我々は、高稼働を有するものを特定し原因を分析し、適切な解決策を見つけるよう。
  • MLeaksFinder
    テンセントメモリリークを見つけるために、オープンソースのツールは、あなたがAPPのプロセスを使用することができ、メモリリークの瞬間リマインダが発生します。
  • Xcodeののメモリーグラフ
    分析されたオブジェクトの参照関係の中で循環させるためMLeaksFinderを補完することができ、メモリリークの側面を見つけるために、このツール。
    また、ライブオブジェクトにいくつかの点を分析することで、あなたは無理が何であるかを分析することができます。

結論するには、高いメモリ使用量につながるいくつかの理由があります。

  • 私たちは、不当なAPIを使用していました
  • 画像は、ダウンロードネットワークへの大きすぎます
  • サードパーティ製のライブラリをキャッシュ
  • 石造レイアウトフレームワーク
  • 永久メモリとして実装パーマネントメモリはオブジェクトの必要はありません、
  • データモデルで冗長フィールド
  • メモリリーク

いくつかの側面から以下の議論。

1.不合理なAPI

ローディング方法:[UIImage imageNamedを]を使用して、一度だけ、または大きな画像のリソースの使用の非常に低い周波数の使用のために1.1、

写真ロードされ、二つの方法があり、1は[UIImage imageNamed:]、システムキャッシュがロードされ、かつ洗浄することができます何のAPIはありません。他のがある[UIImage imageWithContentsOfFile:][[UIImage alloc] initWithContentsOfFile:]、システムが絵が参照されなくなったときのキャッシュ処理、それが占有しません。メモリが完全に解放されます。

上記の特性に基づいて、一度だけ使用するためか、全体像のリソースの使用の非常に低い周波数、あなたは後者を使用する必要があります。後者を使用する場合は、画像への注意を払うには、資産に置くことはできません。

1.2一部の画像自体は、図1の機構を延伸するのに非常に適している。9が、該当する最適化

画像メモリフットプリントは、図の治療機構を延伸するのに適した大きさである。9枚の写真は、それによって実質的にメモリフットプリントを低減する、画像の実際のサイズより少しを切り出すことができます。たとえば、次の絵:



カットは、そのための小さな部分があればとして切り出す際に固体部分は、2本の垂直線との間に図の設計を残しています。その後、我々はストレッチ、ストレッチの部品の一部ではない画像を設定し、Xcodeののスライス機能を使用することができます。画像がロードされると、または通常の方法でロードされました。

必要な症例の非存在下では1.3の使用-[UIColor colorWithPatternImage:]この方法

プロジェクトは、コードがラベルの背景色が画像に設定されている、UILabelを使用しています。上記の方法を使用して、カラー画像をオンにするために。この方法は、画像内のメモリにロードされ、その後、メモリ内の別の画像を作成し、メモリフットプリント画像が大きいであろうを参照します。

解決策:このシナリオでは、UIButtonを使用するのが妥当であるが、画像が背景に設定されています。UIButtonを使用する2つのビューを生成しますが、まだそれは全く価値が、よりUILabelよりも、しかし、画像メモリフットプリントが比較からだろう。

コアグラフィックスAPIを使用する必要がない場合には1.4、物体UIImageの色を変更します

このAPIを使用して、それは、メモリ内の画像を生成し、追加に大きなメモリフットプリントをリードします。合理的なアプローチは次のとおりです。

  • UIViewのセットtintColorプロパティ
  • 写真はUIImageRenderingModeAlwaysTemplateの方法でロードされた
    コード例:
view.tintColor = theColor;
UIImage *image = [[UIImage imageNamed:name] imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate] 

1.5固体の色は、サイズに基づいて、画像が大きすぎ作成します

時々 、私たちは色ベースのUIImageを作成する必要があり、かつ異なる状態でUIButtonの背景画像を使用していました。我々は、唯一の画像の幅と高さを作成する必要が作成する必要があると同じ画像サイズを表示していなかったので、それは、ソリッドカラーの画像ですので1pxのサイズが十分です。
コード例:

//外部应该调用此方法,创建出1px宽高的小图像
+ (UIImage*)createImageWithColor:(UIColor *)color { return [self createImageWithColor: color andSize: CGSizeMake(1, 1)]; } + (UIImage*)createImageWithColor:(UIColor*)color andSize:(CGSize)size { CGRect rect=CGRectMake(0,0, size.width, size.height); UIGraphicsBeginImageContext(rect.size); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, [color CGColor]); CGContextFillRect(context, rect); UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return theImage; } 

1.6勾配画像レベル、オーバーサイズの作成

色に基づいて、いくつかのローカルプロジェクト、コアグラフィックスを使用して、メモリ内の右勾配画像に左から水平方向の作成。画像サイズは、いくつかの大きいケースの観点から、全く小さなメモリのオーバーヘッドを生じないビューのサイズ、です。@オーバーヘッドメモリである例の400x60ビューの大きさに3Xデバイス:
。400 3 * * * 4 3 * 1024分の60 = 210キロバイト
しかし、実際に画像上の、400ピクセルの幅、高さ1ピクセル、完全に同じ効果を得るためには、むしろそれが唯一のメモリオーバーヘッドの場合:
400 * * 1. 1024分の4 = 1.56キロバイト

1.7からUIViewのサブクラスのdrawRectで定義される:ドローにする方法

カスタムのdrawRect APPは、メモリを大量に消費拡大、より多く消費します。:そのメモリ消費量は次のように計算されて
メモリ消費量=(幅*スケール*高さ*スケール* 4/1024/1024)MB

ほとんどすべての場合において、描画需要がCAShapeLayerを通じてこの武器を達成することができます。CPUとメモリフットプリントのCAShapeLayerは、2つの指標のdrawRectを爆破した後、次のとおりです。
それは次のような利点があります。

  • 速いレンダリング。ハードウェアアクセラレーションを使用してCAShapeLayerは、同じグラフィックが速くコアグラフィックスよりも多くのことを描画するために使用されます。
  • メモリの効率的な使用。A CAShapeLayerは、あまりにも多くのメモリを占有しないので、どんなに大きな、グラフィックを作成するように通常の搭乗CALayerの好きではないん。
  • これは、境界層をクリッピングされることはありません。
  • ピクセレーションは発生しません。

1.8からのCALayerサブクラスによって定義される - (無効)drawInContext:メソッドのドロー

そして、類似した上で、描くんCAShapeLayerを使用するようにしてください。

1.9 UILabel特大

UILabelの大きさならば、より大きくintrinsicContentSize、それが不要なメモリ消費の原因となります。だから、ときレイアウトビュー、我々はそれがUILabelのサイズと同じにするために試してみてくださいintrinsicContentSize
この時点では、読者が、その後、簡単な例のプログラムを書くInstrumentsの分析ツールを使用することができ、あなたはこの1つの職業は大幅に増加され、Core Animationの中で割り当てを見ることができます。

1.10はUILabelの背景色を設定します

あなたは背景色がclearColor、whiteColorない設定した場合、メモリのオーバーヘッドが発生する可能性があります。
この場合に遭遇した後、構造は図に変換することができるため、UIView+UILabel背景色のUIViewに設定されているが、唯一の表示テキストUILabelに使用されます。

これは、サンプルプログラムを書き込むことによって、確認するために、楽器のツールを使用しても可能です。

2.ダウンロードした画像が大きすぎます

ほとんどすべてのiOSアプリケーション、ネットワークSDWebImage画像をロードするために、このフレームワークを使用します。時々遭遇したロードされた絵は、この場合には、別のソリューションを使用して、特定のシーンに応じて分析する必要があり、大きすぎます。

2.1ビューの拡大イメージを拡大縮小することができません

大きな画像が合理的であるならば、我々は行うことができます画像をダウンロードすることで、ビューが解放されたときにキャッシュメモリから削除されました。次のようにサンプルコードは次のとおりです。

- (void)dealloc { for (NSString *imageUrl in self.datas) { NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL: [NSURL URLWithString: imageUrl]]; [[SDImageCache sharedImageCache] removeImageForKey: key fromDisk: NO withCompletion: nil]; } } 

コードはそれ以来、メモリが通常の状態に戻ります一度ページが返され、高いメモリ使用量のみページに表示されますことができます。

2.2ビューア小さな、次いで、画像がスケールされるべきです

ビューは小さな画像を表示し、写真をたくさんダウンロードするために使用されている場合、我々は画像がプロセスをズームして、SDWebImageメモリキャッシュに縮小画像を保存する必要があります。
次のようにサンプルコードは次のとおりです。

//为UIImage添加如下分类方法:
- (UIImage*)aspectFillScaleToSize:(CGSize)newSize scale:(int)scale { if (CGSizeEqualToSize(self.size, newSize)) { return self; } CGRect scaledImageRect = CGRectZero; CGFloat aspectWidth = newSize.width / self.size.width; CGFloat aspectHeight = newSize.height / self.size.height; CGFloat aspectRatio = MAX(aspectWidth, aspectHeight); scaledImageRect.size.width = self.size.width * aspectRatio; scaledImageRect.size.height = self.size.height * aspectRatio; scaledImageRect.origin.x = (newSize.width - scaledImageRect.size.width) / 2.0f; scaledImageRect.origin.y = (newSize.height - scaledImageRect.size.height) / 2.0f; int finalScale = (0 == scale) ? [UIScreen mainScreen].scale : scale; UIGraphicsBeginImageContextWithOptions(newSize, NO, finalScale); [self drawInRect:scaledImageRect]; UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return scaledImage; } - (UIImage*)aspectFitScaleToSize:(CGSize)newSize scale:(int)scale { if (CGSizeEqualToSize(self.size, newSize)) { return self; } CGRect scaledImageRect = CGRectZero; CGFloat aspectWidth = newSize.width / self.size.width; CGFloat aspectHeight = newSize.height / self.size.height; CGFloat aspectRatio = MIN(aspectWidth, aspectHeight); scaledImageRect.size.width = self.size.width * aspectRatio; scaledImageRect.size.height = self.size.height * aspectRatio; scaledImageRect.origin.x = (newSize.width - scaledImageRect.size.width) / 2.0f; scaledImageRect.origin.y = (newSize.height - scaledImageRect.size.height) / 2.0f; int finalScale = (0 == scale) ? [UIScreen mainScreen].scale : scale; UIGraphicsBeginImageContextWithOptions(newSize, NO, finalScale); [self drawInRect:scaledImageRect]; UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return scaledImage; } //使用的地方 [self.leftImageView sd_setImageWithURL:[NSURL URLWithString:md.image] placeholderImage:[UIImage imageNamed:@"discover_position"] completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { if (image) { UIImage *scaledImage = [image aspectFillScaleToSize: self.leftImageView.bounds.size scale: 2]; if (image != scaledImage) { self.leftImageView.image = scaledImage; [[SDWebImageManager sharedManager] saveImageToCache: scaledImage forURL: imageURL]; } } }]; 

メカニズムをキャッシュ3.サードパーティライブラリ

3.1 Lottieアニメーションフレームワーク

情報Lottieフレームワークのデフォルトのキャッシュアニメーションフレームなど、アニメーションの多くは、その後、時間の蓄積と、キャッシュ情報が多数存在しますアプリケーションで使用されている場合。しかし、いくつかのキャッシュ後の情報は、もはや使用することができるが、例えば、スプラッシュ画面のページキャッシュの結果をアニメーション。

キャッシュメモリフットプリントについてLottieを引き起こし、そして次のように自分の希望に応じて、二つのアプローチの間で選択します。

  • キャッシュを無効にします
[[LOTAnimationCache sharedCache] disableCaching]; 
  • キャッシュが禁止されていないが、適切なタイミングで、すべてのキャッシュ、キャッシュやアニメーションをクリアします
//清除所有缓存,例如闪屏页在启动以后不会再次访问,那么可以清除此界面的动画所引起的缓存。
[[LOTAnimationCache sharedCache] clearCache]; //从一个页面返回后,可以删除此页面所用动画引起的缓存。 [[LOTAnimationCache sharedCache] removeAnimationForKey:key]; 

3.2 SDWebImage

IO処理ファイルとパフォーマンスを改善することなくアクセスするとき機構は2つのディスクやメモリ、メモリこの層に分割されているキャッシュSDWebImage画像を作ります。デフォルトでは、メモリは解凍後の画像データに格納され、これは巨大なメモリのオーバーヘッドにつながります。あなたが最適化メモリ使用量にしたい場合は、アプリケーションは以下のコードを追加し、スタートアップ圧縮画像データを格納するために選択することができます。

[SDImageCache sharedImageCache].config.shouldDecompressImages = NO; [SDWebImageDownloader sharedDownloader].shouldDecompressImages = NO; 

3.3 YYModel

このライブラリは、高速、使いやすい、非常に良いです。しかし、すべては、二つの側面を持っているクラス情報の内部キャッシュに、コンテンツ属性情報の他のタイプ、およびキャッシュをクリアするには、公開APIを提供していません。これは、ページがメモリのオーバーヘッドを解放することができない原因と、返された場合は特に、これらのキャッシュは常に存在します引き起こす可能性があります。

あなたは、メモリを最適化したいのであれば、手動で解析するのではなく、プロジェクトからフレームを削除することを推奨します。より多くの時間を過ごすために少しを書く時間が、しかし、CPUやメモリの性能上、最高です。

4.Masonryレイアウトフレームワーク

このフレームワークは、それは確かに非常に良いですが、ほぼすべてのAPPが導入され、使用頻度の高いですが、いくつかの問題があります。

  • あなたはスーパー、またはパラメータがnilでない場合は、簡単にクラッシュにつながります。
  • 実装プロセスでは、フレームベースのオーバーヘッドの多くのレイアウトよりも小さなオブジェクトの多くを作成します。

だから、私の考えでは、それはメモリのオーバーヘッドをもたらしますので、それを解放することができない、解放されません、それは何か少し使用べきではない、特に一部のページでは、このフレームワークを使用することができることであるが、その使用を減らす必要があります。

永久メモリとして実装5被写体永久記憶する必要はありません、

サイドバーなどのために、ActionSheetこのインタフェースオブジェクトは、永久的なメモリを達成していない、もはや破壊のために費やされた時間を使用するために作成されるべきではありません。

データモデル内の6冗長フィールド

モデルを解析する際に、反復のバージョンでは、サーバから返されたデータについては、いくつかのフィールドはもはや使用されているが存在しない場合があります。そのようなモデルがモデルで冗長フィールドの後、クリーンアップ、多数のオブジェクトが生成されます場合は、メモリー・フットプリントの一定量を節約することができます。

7.メモリリーク

メモリリークは、アプリケーションのメモリ使用量が増加し、減少していないされていますが発生します。実務における痛みポイントは次のとおり固定メモリリーク前足、後足は、別の開発者誤ってメモリリークが再び発生し、その結果、自己のブロックに書き込み、又はインスタンス変数への参照。

これに基づき、プロジェクトの導入ReactiveObjC 2つの牛Xのマクロ、@ weakify、@strongify、および以下の文言の仕様:

  • ブロック外用@weakify(自己)では、複数の弱参照を定義することができます。
  • ブロックの内部の先頭に@strongify(自己)を使用し、一つは強い参照を複数定義することができます。
  • ブロック内の使用セルフ書き込みコード
  • ブロック内部のアクセスクラスでの非インスタンス変数

チーム内の上記仕様を実装し、効果的に循環参照が発生するのを防止することができます。



著者:buptwsgの
リンクします。https://www.jianshu.com/p/8662b2efbb23
出典:ジェーンの本が
著者によって著作権で保護されています。著者は認可商業転載してください接触、非商用の転載は、ソースを明記してください。

 

おすすめ

転載: www.cnblogs.com/sundaysgarden/p/12149034.html