Objective-Cのメモリオーバーフローの問題のエクスペリエンスの概要

iOSプラットフォームのメモリ使用量参照カウントメカニズム、および半自動リリースメカニズムの導入。この使用法の多様性により、開発者はメモリリークとメモリ使用量の不可解なメモリ増加を非常に引き起こしやすくなります。この記事ではiOSプラットフォームを紹介します。メモリ使用の原則と使用トラップ、自動解放メカニズムの詳細分析、メモリ不足アラーム後の処理フロー、独自の例と組み合わせて、メモリサージの問題追跡レコードと関連ツールの使用を紹介します
。iOSプラットフォームの開発者としてのiOSプラットフォームの
一般的なメモリの問題、メモリの問題に悩まされたことはありますか?不可解なメモリの継続的な増加、プログラムの不可解なクラッシュ、不可解なメモリリークはすべて、iOSプラットフォームのメモリに関連する一般的な問題です。この記事では、iOSプラットフォームのメモリ管理メカニズム、自動解放メカニズム、およびメモリ使用量トラップについて詳しく説明します。 iOSプラットフォームのメモリに関する問題のほとんどが解決され、プログラムの安定性が向上します; 
1 
iOSプラットフォームのメモリ管理の概要iOSプラットフォームのメモリ管理は参照カウントメカニズムを使用します; allocまたはallWithZoneメソッドを使用してオブジェクトが作成されると、参照カウントは+1になります。releaseメソッドを使用してオブジェクトを解放すると、参照カウントは-1になります。これは、各オブジェクトがそれを参照する他のオブジェクトの数を追跡し、参照カウントが0に達すると、オブジェクトのメモリが解放されることを意味します。さらに、iOSには遅延リリースメカニズムAutoReleaseも用意されています。iOSプラットフォームでのメモリ管理の多様性により、開発者はこの方法で要求されたメモリを手動で解放する必要がなく、システムは特定の時間にメモリを解放します。 、開発者にメモリリークでのメモリリークまたは不可解なプログラムクラッシュを簡単に体験させる。この記事では、iOSプラットフォームメモリの使用法の仕様と手法、およびツールを使用して問題を回避または検出する方法を詳しく紹介します
。2iOSプラットフォームのメモリ使用法の原則
2.1オブジェクト所有権と破壊
2.1.1誰がそれを作成してリリースしたか。
如果是以alloc,new或者copy,mutableCopy创建的对象,则必须调用release或者autorelease方法释放内存;
如果没有释放,则导致内存泄漏!
2.1.2 谁retain,谁释放; 
如果对一个对象发送 retain消息,其引用计数会+1,则使用完必须发送release或者autorelease方法释放内存或恢复引用计数;
如果没有释放,则导致内存泄漏!
2.1.3 没创建且没retain,别释放; 
不要释放那些不是自己alloc或者retain的对象,否则程序会crash;
不要释放autorelease的对象,否则程序会crash;
2.2 对象的深拷贝与浅拷贝 
一般来说,复制一个对象包括创建一个新的实例,并以原始对象中的值初始化这个新的实例。 复制非指针型实例变量的值很简单,比如布尔,整数和浮点数。复制指 针型实例变量有两种方法。一种方法称为浅拷贝,即将原始对象的指针值复制到副本中。因此,原始对象和副本共享引用数据。另一种方法称为深拷贝,即复制指针 所引用的数据,并将其赋给副本的实例变量。
2.2.1 深拷贝 
深拷贝的流程是 先创建一个新的对象且引用计数为1,并用旧对象的值初始化这个新对象;
ClassA* objA = [[ClassA alloc] init];
ClassA* objB = [objA copy];
objB是一个新对象,引用计数为1,且objB的数据等同objA的数据;
注意: objB需要释放,否则会引起内存泄漏!
2.2.2 浅拷贝 
浅拷贝的流程是,无需引入新的对象,把原有对象的引用计数+1即可
ClassA* objA = [[ClassA alloc] init];
ClassA* objB = [objA retain];
注意: objB需要释放,恢复objA的引用计数,否则会引起内存泄漏!
2.3对象的存取方法2.3.1 属性声明和实现 
变量声明的常用属性类型包括readonly,assign,retain和copy;且系统会自动为声明了属性的变量生成set和get函数;
readonly属性: 只能读,不能写;
assign属性: 是默认属性,直接赋值,没有任何保留与释放问题;
retain属性: 会增加原有对象的引用计数并且在赋值前会释放原有对象,然后在进行赋值;
copy属性:  会复制原有对象,并在赋值前释放原有对象,然后在进行赋值;
2.3.2 使用属性声明可能带来的隐患 
当一个非指针变量使用retain(或者copy)这个属性时,尽量不要显性的release这个变量;直接给这个变量置空即可;否则容易产生过度释放,导致程序crash; 例如:
ClassA类的strName是NSString* 类型的变量且声明的属性为retain;
ClassA.strName = nil;  /* 释放原有对象且对此对象赋值为空 */
[ClassA.strName release]; /* strName内存可能已经被释放过了,将导致程序crash */
Assign这个属性一般是非指针变量(布尔类型,整形等)时用这个类型;属于直接赋值型,不需要考虑内存的保留与释放;
如果一个指针类型的变量使用assign类型的属性,有可能引用已经释放的变量;导致程序crash; 例如:
ClassB* obj =[[[ClassB alloc] init] autorelease];
……
ClassA.strName = obj; /* strName 指向obj的内存地址*/
后续在使用ClassA.strName的时候, 因为obj是autorelease的,可能obj的内存已经被回收;导致引用无效内存,程序crash;
3iOS平台AutoRelease机制3.1 自动释放池的常见问题 
大家在开发iOS程序的时候,是否遇到过在列表滑动的情况内存莫名的增长,频繁访问图片的时候内存莫名的增长,频繁的打开和关闭数据库的时候内存莫名的增长…… 这些都是拜iOS的autorelease机制所赐;具体分析如下:
1: 滑动列表的时候,内存出现莫名的增长,原因可能有如下可能:
1:没有使用UITableView的reuse机制; 导致每显示一个cell都用autorelease的方式重新alloc一次; 导致cell的内存不断的增加;
2:每个cell会显示一个单独的UIView, 在UIView发生内存泄漏,导致cell的内存不断增长;
2:画像に頻繁にアクセスすると、メモリが不可解に増大します
频繁的访问网络图片,导致iOS内部API,会不断的分配autorelease方式的buffer来处理图片的解码与显示; 利用图片cache可以缓解一下此问题;
.3:SQLiteを頻繁に開閉すると、メモリが継続的に増大します; 
SQLiteが頻繁に開閉され、読み取りと書き込み用のデータバッファーが大きいため、SQLiteは開いたり閉じたりすると、自動解放を使用して51Kのメモリが割り当てられます。アクセス時間が多い場合、メモリはすぐに数十メガバイト、さらには数百メガバイトに達します。したがって、データベースと大きなデータバッファーの頻繁な読み取りと書き込みの場合、SQLiteの長い接続モードを設定できます;データベースの頻繁なオープンとクローズを回避します; 
3.2自動リリースプール
NSAutoreleasePool の概念には、サウンドを保存するための配列(NSMutableArray)が含まれていますautoreleaseという名前のすべてのオブジェクト。オブジェクトが自動解放として宣言されている場合、システムによって行われる作業は、このオブジェクトをこの配列に追加することです。
ClassA * obj1 = [[[ClassA alloc] init] autorelease]; //保持カウント= 1、このオブジェクトを自動解放プールに
追加NSAutoreleasePool自体が破棄されるときにこの配列をトラバースし、配列内の各メンバーを解放します。配列内のメンバーの保持カウントが1の場合、リリース後、保持カウントは0になり、オブジェクトは正式に破棄されます。配列内のメンバーの保持カウントが1より大きい場合、リリース後、保持カウントは0より大きくなり、オブジェクトはまだ破棄されず、メモリリークが発生します。
3.3自動リリースプールの範囲とネスト
AutoreleasePoolはネストして使用できます。
池是被嵌套的,嵌套的结果是个栈,同一线程只有当前栈顶pool实例是可用的:
 
当短生命周期内,比如一个循环中,会产生大量的临时内存,可以创建一个临时的autorelease pool,这样可以达到快速回收内存的目的;
3.4 自动施放池的手动创建与自动创建
3.4.1 需要手动创建自动释放池
●如果你正在编写一个不是基于Application Kit的程序,比如命令行工具,则没有对自动释放池的内置支持;你必须自己创建它们。
●如果你生成了一个从属线程,则一旦该线程开始执行,你必须立即创建你自己的自动释放池;否则,你将会泄漏对象。
●如果你编写了一个循环,其中创建了许多临时对象,你可以在循环内部创建一个自动释放池,以便在下次迭代之前销毁这些对象。这可以帮助减少应用程序的最大内存占用量。
3.4.2 系统自动创建自动释放池 
Application Kit会在一个事件周期(或事件循环迭代)的开端—比如鼠标按下事件—自动创建一个自动释放池,并且在事件周期的结尾释放它.
4 iOS平台内存使用陷阱
4.1 重复释放 
在前文已经提到,不要释放不是自己创建的对象;
释放自己的autorelease对象,app会crash;
释放系统的autorelease对象,app会crash;
4.2 循环引用  

循环引用,容易产生野引用,内存无法回收,最终导致内存泄漏!可以通过弱引用的方式来打破循环引用链;所谓的弱引用就是不需要retain,直接赋值的方式,这样的话,可以避免循环引用的问题,但是需要注意的是,避免重复释放的问题;
5 iOS平台内存报警机制 
由于iOS平台的内存管理机制,不支持虚拟内存,所以在内存不足的情况,不会去Ram上 创建虚拟内存;所以一旦出现内存不足的情况,iOS平台会通知所有已经运行的app,不论是前台app还是后台挂起的app,都会收到 memory warning的notice;一旦app收到memory warning的notice,就应该回收占用内存较大的变量;
5.1 内存报警处理流程 
1: app收到系统发过来的memory warning的notice;
2: app释放占用较大的内存;
3: 系统回收此app所创建的autorelease的对象;
4: app返回到已经打开的页面时,系统重新调用viewdidload方法,view重新加载页面数据;重新显示;
5.2 内存报警测试方法 
在Simulate上可以模拟低内存报警消息;
iOS模拟器 -> 硬件 -> 模拟内存警告;
开发者可以在模拟器上来模拟手机上的低内存报警情况,可以避免由于低内存报警引出的app的莫名crash问题;
6 iOS平台内存检查工具
6.1 编译和分析工具Analyze 
iOS分析ツールは、コンパイル時の警告、メモリリークの隠れた危険を検出し、ロジックの問題をチェックアウトすることもできます。したがって、Analyzeによって検出された問題は、重大なバグを回避するためにセルフテスト段階で解決する必要があります。
内存泄漏隐患提示:
Potential Leak of an object allocated on line ……
データ割り当てのヒントの隠れた危険:
……の左のオペランドはガベージ値です。オブジェクト参照のハザードヒント:
リリース後にReference-Countedオブジェクトが使用されます; 
上記のヒントはすべて深刻であり、深刻な問題を引き起こす可能性があります。開発者は細心の注意を払う必要があります!
6.2 メモリ検出ツール 
6.2.1メモリリーク検出ツール—リー
クリークツールは、すべてのメモリリークを簡単にカウントできます。また、そのファイルでメモリリークが発生しているコード行を表示できるため、問題を特定しやすくなり、側面も増えます。 ;ただし、リークがメモリリークをカウントすると、自動解放モードでメモリもカウントされます。したがって、メモリリークを探すときは、自動解放の状態を無視できます。
リークツール:リークツールを使用
して、コード内のメモリをすばやく見つけることができますリークは、ツールを使用して、メモリリークが発生しているコードセグメントをすばやく見つけることができます
。6.2.2メモリサージ検出
ツール—割り当て割り当てツールは割り当てられたすべてのメモリポイントを簡単に一覧表示できるため割り当てられたメモリサイズでソートできます。このようにして、最も多くのメモリが割り当てられ、継続的に割り当てられているポイントを簡単に見つけることができるため、より大きなメモリを継続的に割り当てているこれらの場所を分析できます。



 
このツールは、メモリが適用されているすべての場所を表示し、アプリケーションの数とサイズをカウントします。このリストから、最もメモリの多いアプリケーションと最もメモリの多いアプリケーションのステートメントを見つけ、どの場所が最もメモリを使用しているかを分析し、最適化します。そして改善;

おすすめ

転載: blog.csdn.net/qq_27740983/article/details/50125223