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(