请问Objective-c 内存溢出问题经验汇总,那个好心人共享一下

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请问Objective-c 内存溢出问题经验汇总,那个好心人共享一下相关的知识,希望对你有一定的参考价值。

ios平台的内存使用引用计数的机制,并且引入了半自动释放机制;这种使用上的多样性,导致开发者在内存使用上非常容易出现内存泄漏和内存莫名的增 长情况; 本文会介绍iOS平台的内存使用原则与使用陷阱; 深度剖析autorelease机制;低内存报警后的处理流程;并结合自身实例介绍内存暴增的问题追查记录以及相关工具的使用情况;
iOS平台内存常见问题
作为iOS平台的开发者,是否曾经为内存问题而苦恼过?内存莫名的持续增长,程序莫名的 crash,难以发现的内存泄漏,这些都是iOS平台内存相关的常见问题;本文将会详细介绍iOS平台的内存管理机制,autorelease机制和内存 的使用陷阱,这些将会解决iOS平台内存上的大部分问题,提高了程序的稳定性;
1 iOS平台内存管理介绍
iOS平台的内存管理采用引用计数的机制;当创建一个对象时使用alloc或者allWithZone方法时,引用计数就会+1;当释放对象使用release方法时,引用计数就是-1; 这就意味着每一个对象都会跟踪有多少其他对象引用它,一旦引用计数为0,该对象的内存就会被释放掉;另外,iOS也提供了一种延时释放的机制 AutoRelease,以这种方式申请的内存,开发者无需手动释放,系统会在某一时机释放该内存; 由于iOS平台的这种内存管理的多样性,导致开发者在内存使用上很容易出现内存泄漏或者程序莫名崩溃的情况,本文会详细介绍iOS平台内存的使用规范与技 巧以及如何利用工具避免或者发现问题;
2 iOS平台内存使用原则
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频繁打开和关闭操作,而且读写的数据buffer较大,那么 SQLite在每次打开与关闭的时候,都会利用autorelease的方式分配51K的内存; 如果访问次数很多,内存马上就会顶到几十兆,甚至上百兆! 所以针对频繁的读写数据库且数据buffer较大的情况, 可以设置SQLite的长连接方式;避免频繁的打开和关闭数据库;
3.2 自动释放池的概念
NSAutoreleasePool内部包含一个数组(NSMutableArray),用来保存声名为autorelease的所有对象。如果一个对象声明为autorelease,系统所做的工作就是把这个对象加入到这个数组中去。
ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1,把此对象加入autorelease pool中
NSAutoreleasePool自身在销毁的时候,会遍历一遍这个数 组,release数组中的每个成员。如果此时数组中成员的retain count为1,那么release之后,retain count为0,对象正式被销毁。如果此时数组中成员的retain count大于1,那么release之后,retain count大于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的分析工具可以发现编译中的warning,内存泄漏隐患,甚至还可以检查出logic上的问题;所以在自测阶段一定要解决Analyze发现的问题,可以避免出现严重的bug;
内存泄漏隐患提示:
Potential Leak of an object allocated on line ……
数据赋值隐患提示:
The left operand of …… is a garbage value;
对象引用隐患提示:
Reference-Counted object is used after it is released;
以上提示均比较严重,可能会引起严重问题,需要开发者密切关注!
6.2 内存检测工具
6.2.1 内存泄漏检测工具—Leak
Leak工具可以很容易的统计所有内存泄漏的点,而且还可以显示在那个文件,哪行代码有 内存泄漏,这样定位问题比较容易,也比较方面;但是Leak在统计内存泄漏的时候会把autorelease方式的内存也统计进来; 所以我们在查找内存泄漏情况的时候,可以autorelease的情况忽略掉;
Leak工具:

通过Leak工具可以很快发现代码中的内存泄漏,通过工具也可以很快找到发生内存泄漏的代码段:

6.2.2 内存猛增检测工具—Allocations
Allocations工具可以很容易的列出所有分配内存的点,这样我们可以按照分配内存大小来进行排序, 这样可以很容易的发现哪些点分配的内存最多,而且是持续分配,这样我们来针对性的分析这些持续分配较大内存的地方;

此工具会显示出所有申请内存的地方,并统计申请的次数和大小; 从这个列表中可以找出内存申请次数最多且申请内存最大的语句;从而分析出哪些地方使用的内存最多,进而可以优化和改进;
参考技术A 现在大概知道有以下几种:
1 非ARC模式下, release忘了.
2 少用[UIImage imageNamed]
3 后台线程的时候,忘了加AutoReleasePool

其实,工程到最后, 可以Cmd+Shift+B 来看一下有多少蓝色的部分.
尽量保持没有蓝色吧

Swift 项目兼容 Objective-C 问题汇总

版权申明:作者 已将本文在微信公众平台的发表权「独家代理」给 iOS 开发(iOSDevTips)微信公共帐号。本文的所有打赏归一叶所有。

作者介绍:一叶,四年 iOS 开发,曾就职盛大文学,现工作于奇点国际,热爱移动互联网,内存分析及性能优化经验丰富,擅长重构、接口设计、框架搭建,欢迎访问博客

一、解决问题

Swift 项目需要使用封装好的 Objective-c 组件、第三方类库,苹果提供的解决方案能够处理日常大部分需求,但还不能称之为完美,混编过程中会遇到很多问题。本文将 Swift 兼容 Objective-c 的问题汇总,以帮助大家更好的使用 Swift,内容列表如下:

1. Swift 调用 Objective-c 代码
2. Objective-c 调用 Swift 代码
3. Swift 兼容 Xib/Storyboard
4. Objective-c 巧妙调用不兼容的 Swift 方法
5. 多 Target 编译错误解决
6. 第三方类库支持

二、基础混合编程

Swift 与 Objective-c 的代码相互调用,并不像 Objective-c 与 C/C++ 那样方便,需要做一些额外的配置工作。无论是 Swift 调用 Objective-c 还是 Objective-c 调用 Swift,Xcode 在处理上都需要两个步骤:

2.1 Swift 调用 Objective-c 代码

Xcode 对于 Swift 调用 Objective-c 代码,除宏定义外,其它支持相对完善。

2.1.1 使用 Objetvie-c 的第一步,

告诉 Xcode、哪些 Objective-c 类要使用,新建 .h 头文件,文件名可以任意取,建议采用 “ 项目名-Bridging-Header.h” 命令格式。

Swift 项目兼容 Objective-C 问题汇总

Tips

Swift 之 IOS 项目,在 Xcode6 创建类文件,默认会自动选择 OS X 标签下的文件,这时 一定要选择 iOS 标签 下的文件,否则会出现语法智能提示不起作用,严重时会导致打包出错。

2.1.2 第二步,Target 配置,使创建的头文件生效

Swift 项目兼容 Objective-C 问题汇总

设置 Objective-C Bridging Header 时,路径要配置正确,例如:创建的名为 “ILSwift-Bridging-Header.h” 文件,存于 ILSwift 项目文件夹的根目录下,写法如下:

ILSwift/ILSwift-Bridging-Header.h

当然,在新项目中,直接创建一个 Objective-c 类,Xcode 会提示:

Swift 项目兼容 Objective-C 问题汇总

直接选择 Yes 即可,如果不小心点了其它按钮,可以按照上面的步骤一步一步添加。

2.2 Objective-c 调用 Swift 代码

2.2.1 Objective-c 调用 Swift 代码两个步骤

第一步告诉 Xcode 哪些类需要使用 (继承自 NSObject 的类自动处理,不需要此步骤),通过关键字 @objc(className) 来标记

import UIKit@objc(ILWriteBySwift)class ILWriteBySwift {
   var name: String!   class func newInstance() -> ILWriteBySwift {
       return ILWriteBySwift()
   }
}

第二步引入头文件,Xcode 头文件的命名规则为

$(SWIFT_MODULE_NAME)-Swift.h

示例如下:

#import "ILSwift-Swift.h"
Tips

不清楚 SWIFT_MODULE_NAME 可通过以下步骤查看

Swift 项目兼容 Objective-C 问题汇总

2.2.2 找不到 $(SWIFT_MODULE_NAME)-Swift.h

Swift 项目兼容 Objective-C 问题汇总

  1. 遇到此问题可按以下步骤做常规性检查

    1. 确定导入 SWIFT_MODULE_NAME)-Swift.h 头文件的文件名正确
      2.SWIFT_MODULE_NAME)-Swift.h 在 clean 后没有重新构建,执行 Xcode->Product->Build

  2. 头文件循环

在混合编程的项目中,由于两种语言的同时使用,经常会出现以下需求:在 Swift 项目中需要使用 Objectvie-c 写的 A 类,而 A 类又会用到 Swift 的一些功能,头文件的循环,导致编译器不能正确构建 $(SWIFT_MODULE_NAME)-Swift.h,遇到此问题时,在 .h 文件做如下处理

// 删除以下头文件
//#import "ILSwift-Swift.h"
// 通过代码导入类
@class ILSwiftBean;

在 Objevtive-c 的 .m 文件最上面,添加

#import "ILSwift-Swift.h"

出现 Use of undecalared identifier 错误或者找不到方法,如下:

Swift 项目兼容 Objective-C 问题汇总

引起的原因有以下几种可能:

1. 使用的 Swift 类不是继承自 NSObject,加入关键字即可
2.SWIFT_MODULE_NAME)-Swift.h 没有实时更新,Xcode->Product->Build
3. 此 Swift 文件中使用了 Objective-c 不支持的类型或者语法,如 private

出现 部分方法找不到 的问题,Xcode 无智能提示:

此方法使用了 Objective-c 不支持的类型或者语法

苹果官方给出的不支持转换的类型

Generics

Tuples

Enumerations defined in Swift

Structures defined in Swift

Top-level functions defined in Swift

Global variables defined in Swift

Typealiases defined in Swift

Swift-style variadics

Nested types

Curried functions

三、Xib/StoryBoard 支持

Swift 项目在使用 Xib/StoryBoard 时,会遇到两种不同的问题

1.Xib:不加载视图内容
2.Storyboard:找不到类文件

3.1 Xib 不加载视图内容

在创建 UIViewController 时,默认选中 Xib 文件,在 Xib 与类文件名一致时,可通过以下代码实例化:

let controller = ILViewController()

运行,界面上空无一物,Xib 没有被加载。解决办法,在类的前面加上 @objc(类名),例如:

import UIKit@objc(ILViewController)class ILViewController: UIViewController {}

Tips:

StoryBoard 中创建的 UIViewController,不需要 @objc(类名) 也能够保持兼容

3.2 Storyboard 找不到类文件

Swift 语言引入了 Module 概念,在通过关键字 @objc(类名) 做转换的时候,由于 Storboard 没有及时更新 Module 属性,会导致如下两种类型错误:

3.2.1 用 @objc(类名) 标记的 Swift 类或者 Objective-c 类可能出现错误:

2015-06-02 11:27:42.626 ILSwift[2431:379047] Unknown class _TtC7ILSwift33ILNotFindSwiftTagByObjcController in Interface Builder file.

解决办法,按下图,选中 Module 中的空白,直接回车

Swift 项目兼容 Objective-C 问题汇总

3.2.2 无 @objc(类名) 标记的 Swift 类

2015-06-02 11:36:29.788 ILSwift[2719:417490] Unknown class ILNotFindSwiftController in Interface Builder file.

解决办法,按下图,选择正确的 Module

Swift 项目兼容 Objective-C 问题汇总

  1. 产生上面错误的原因:
    在设置好 Storyboard 后,直接在类文件中,添加或者删除 @objc(类名) 关键字,导致 Storyboard 中 Module 属性没有自动更新,所以一个更通用的解决办法是,让 Storyboard 自动更新 Module, 如下:

Swift 项目兼容 Objective-C 问题汇总

3.3 错误模拟 Demo 下载

为了能够让大家更清楚的了解解决流程,将上面的错误进行了模拟,想动手尝试解决以上问题的同学可以直接下载

四、Objective-c 巧妙调用不兼容的 Swift 方法

在 Objective-c 中调用 Swift 类中的方法时,由于部分 Swift 语法不支持转换,会遇到无法找到对应方法的情况,如下:

import UIKitenum HTTPState {   case Succed, Failed, NetworkError, ServerError, Others}class ILHTTPRequest: NSObject {

   class func requestLogin(userName: String, password: String, callback: (state: HTTPState) -> (Void)) {
       dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in
           NSThread.sleepForTimeInterval(3)
           dispatch_async(dispatch_get_main_queue(), { () -> Void in
               callback(state: HTTPState.Succed)
           })
       })
   }

}

对应的 $(SWIFT_MODULE_NAME)-Swift.h 文件为:

SWIFT_CLASS("_TtC12ILSwiftTests13ILHTTPRequest")@interface ILHTTPRequest : NSObject- (SWIFT_NULLABILITY(nonnull) instancetype)init OBJC_DESIGNATED_INITIALIZER;@end

从上面的头文件中可以看出,方法 requestLogin 使用了不支持的 Swift 枚举,转换时方法被自动忽略掉,有以下两种办法,可以巧妙解决类似问题:

4.1 用支持的 Swift 语法包装

在 Swift 文件中,添加一个可兼容包装方法 wrapRequestLogin, 注意此方法中不能使用不兼容的类型或者语法

import UIKitenum HTTPState: Int {   case Succed = 0, Failed = 1, NetworkError = 2, ServerError = 3, Others = 4}class ILHTTPRequest: NSObject {

   class func requestLogin(userName: String, password: String, callback: (state: HTTPState) -> (Void)) {
       dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in
           NSThread.sleepForTimeInterval(3)
           dispatch_async(dispatch_get_main_queue(), { () -> Void in
               callback(state: HTTPState.Succed)
           })
       })
   }   class func wrapRequestLogin(userName: String, password: String, callback: (state: Int) -> (Void)) {
       self.requestLogin(userName, password: password) { (state) -> (Void) in
           callback(state: state.rawValue)
       }
   }

}

对应的 $(SWIFT_MODULE_NAME)-Swift.h 文件为:

SWIFT_CLASS("_TtC12ILSwiftTests13ILHTTPRequest")@interface ILHTTPRequest : NSObject+ (void)wrapRequestLogin:(NSString * __nonnull)userName password:(NSString * __nonnull)password callback:(void (^ __nonnull)(NSInteger))callback;
- (SWIFT_NULLABILITY(nonnull) instancetype)init OBJC_DESIGNATED_INITIALIZER;@end

此时,我们可以在 Objective-c 中直接使用包装后的方法 wrapRequestLogin

4.2 巧妙使用继承

使用继承可以支持所有的 Swift 类型,主要的功能在 Objective-c 中实现,不支持的语法在 Swift 文件中调用,例如,ILLoginSuperController 做为父类

@interface ILLoginSuperController : UIViewController
@property (weak, nonatomic) IBOutlet UITextField *userNameField;
@property (weak, nonatomic) IBOutlet UITextField *passwordField;

- (IBAction)loginButtonPressed:(id)sender;
@end

////////////////////////////////////////////////////////////////

@implementation ILLoginSuperController

- (IBAction)loginButtonPressed:(id)sender
{
}
@end

创建 Swift 文件,继承自 ILLoginSuperController,在此 Swift 文件中调用那些不支持的语法

import UIKit

class ILLoginController: ILLoginSuperController {

   override func loginButtonPressed(sender: AnyObject!) {
       ILHTTPRequest.requestLogin(self.userNameField.text, password: self.passwordField.text) { (state) -> (Void) in
           // 具体业务逻辑
       }
   }

}

五、多 Target 编译错误解决

在使用多 Target 时,会出现一些编译错误

5.1 Use of undeclared type

Swift 项目兼容 Objective-C 问题汇总

此类错误,是因为当前运行的 Target 找不到必须编译文件。将文件添加到 Target 即可,如下支持 ILSwiftTests Target,选中 ILSwiftTests 前的复选框即可

Swift 项目兼容 Objective-C 问题汇总

5.2 does not have a member named

Swift 项目兼容 Objective-C 问题汇总

此类错误可能由于如下两种原因引起,解决办法同上:

1. 此方法来自父类,父类文件没有加入到当前 Target
2. 此方法来自扩展,扩展没有加入到当前 Target

Tips

如果检查发现,所有的类文件都已经准确添加到 Target 中,但编译还是不通过,此时着重检查桥接文件是否正确设置,是否将相应的头文件加入到了桥接文件中。如无特别要求,建议将所有 Target 的桥接文件全都指向同一文件。关于桥接文件的设置,请参考 2.1

六、第三方类库支持

Swift 项目取消了预编译文件,一些第三方 Objective-c 库没有导入必要框架 (如 UIKit) 引起编译错误

6.1 Cocoapods 找不到 .o 文件

在使用了 Cocoapods 项目中,会出现部分类库的 .o 文件找不到,导致此种错误主要是以下两种问题:

1. 类库本身存在编译错误
2.Swift 没有预编译,UIKit 等没有导入

将此库文件中的代码文件直接加到项目中,编译,解决错误

6.2 JSONModel 支持

在 Swift 中可以使用 JSONModel 部分简单功能,一些复杂的数据模型建议使用 Objevtive-c

import UIKit@objc(ILLoginBean)
public class ILLoginBean: JSONModel {
   var userAvatarURL: NSString?
   var userPhone: NSString!
   var uid: NSString!

}

Tips

在 Swift 使用 JSONModel 框架时,字段只能是 NSFoundation 中的支持类型,Swift 下新添加的 String、Int、Array 等都不能使用

6.3 友盟统计

Swift 项目中引入友盟统计 SDK 会出现 referenced from 错误:

解决办法,找到 Other Linker Flags,添加 -lz

七、综述

现在大部分成熟的第三方框架都是使用 Objective-c 写的,开发时不可避免的涉及到两种语言的混合编程,期间会遇到很多奇怪的问题。因为未知才有探索的价值,Swift 的简洁快速,能够极大的推进开发进度。所以从今天开始,大胆的开始尝试。

以上是关于请问Objective-c 内存溢出问题经验汇总,那个好心人共享一下的主要内容,如果未能解决你的问题,请参考以下文章

由于 Objective-C 中的整数溢出,处理和报告内存分配错误的最佳方法是啥?

内存溢出的预防及解决汇总

Jmeter中outofmemoryError内存溢出、数组越界等问题汇总

java内存区域/内存溢出汇总

内存管理:避免内存溢出和频繁的垃圾回收

java内存溢出问题