swift 获取mac地址有内存泄露的地址怎么办

swift出现内存泄漏怎么办
[问题点数:100分]
swift出现内存泄漏怎么办
[问题点数:100分]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
匿名用户不能发表回复!|内存泄露、内存溢出以及解决方法
内存泄露是指程序在运行过程中动态申请的内存空间不再使用后没有及时释放,从而很可能导致应用程序内存无线增长。更广义的内存泄露包括未对系统的资源的及时释放,比如句柄等。
内存溢出即用户在对其数据缓冲区操作时,超过了其缓冲区的边界;尤其是对缓冲区写操作时,缓冲区的溢出很可能导致程序的异常。
一.内存泄露
“知己知彼,方能百战不殆”,如果我们能够比较清楚的了解在编程的时候哪些情况容易导致内存泄露,通过避免这些糟糕的情况,从提高代码的质量本身出发,来抵御潜在导致内存泄露的发生。
1.1先来看看内存泄露可能发生的一些场景:
(1)程序员常常忽略在所有的分支都加上内存的回收处理
int size = 100;
char *pointer = new char[size];
if (!xxxAPI(pointer, size)
(2)构造函数中申请空间,析构函数中释放空间
(3)库函数或者系统API会在内部申请空间,然后返回指针给用户;以strdup为例
str = strdup("hello World!");
strdup申请了一段空间存储字符串"hello World",然后返回空间地址,这个时候用户经常会忘记释放str;
上面只是列出了简单的三种情况,尤其在一个复杂的大型系统中,一段内存的使用周期太长或者嵌套太深,还需要程序员自己去把握。
1.2.内存泄露的检测
(1)利用内存泄露检测工具
常用的有 BoundsCheaker、Deleaker、Visual Leak Detector等,工具毕竟熟能生巧,用户选择先自己喜欢的一款去用即可。
BoundsChecker没有找到win7下支持VS2005的破解版,用盗版的伤不起啊。
(2)使用Deleaker(本文采用vs2005)进行内存泄露检查
如下图所示:
A) Deleak安装后自动集成到VS中,在VS“工具”菜单中会加入一个“Deleaker”菜单项。
B) Deleaker能够对GDI,USER对象以及句柄进行检测,是否及时释放。
C) Deleaker能够检测泄露的内存发生地点,即展示其函数栈;双击能够转到相应的文件;
PS:Deleaker对中文不支持
如果有内存泄露Deleaker会在程序调试完弹出对话框如下图所示:
(3)使用Viual Leak detector
使用Deleak方便灵活,除了其对中文路径支持问题,但感觉和vs的集成度并不是很高。
Viual Leak detector安装后,要在VS中设置相应的头文件和库路径,在Debug模式下如果要检测相应源文件的内存泄露,则加上"#include &vld.h&"即可;
这样在检测内存泄露,可以在VS的输出窗口进行输出,感觉和VS的集成度更高,结果如下图所示:
同样能够显示 内存泄露处的 调用栈,并且通过双击也可以跳转到文件的内存泄露行,个人还是比较喜欢这种方式的。
(4)在没有工具的情况下,使用crtdbg.h中的api也是个很棒的选择
在MFC中可以看到在程序退出的时候,输出框内结尾部分输出内存泄露,并且点击可以跳转到内存泄露的代码处。
那么在console程序下呢,当然我们同样可以做到(做那些MFC帮我们完成了的细节);
A) _CrtSetDbgFlag函数
int _CrtSetDbgFlag(
int newFlag
(函数详细信息参考:)
这个函数用于控制debug模式下堆管理的分配行为;
在main函数开始处添加:
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
//_CRTDBG_REPORT_FLAG:表示获取当前的标示位
//_CRTDBG_LEAK_CHECK_DF:表示检测内存泄露
则如果出现内存泄露Debug结束后,输出框将输出:
{150}表示申请的第150块申请的内存空间;
B) 显示内存泄露所在的文件以及行
能够知道有内存泄露是不够的,更需要的信息是哪里内存泄露了?
我们可以在每个源文件的开头定义写这样一条宏定义:
//根据__FILE___和__LINE__能够确定文件和行
#define new
new(_NORMAL_BLOCK, __FILE__, __LINE__)
C) 显示内存泄露处的堆栈
//lBreakAlloc,在申请的堆区序号为lBreakAlloc处设置一个断点
long _CrtSetBreakAlloc( long lBreakAlloc );
(函数详细信息参考:)
此函数在指定的申请堆区空间次序处(即lBreakAlloc)设置断点;
很喜欢这个函数,这个函数结合"A)"中提到的{150},比如使用方法:
_CrtSetBreakAlloc(150); //则在第150次申请堆空间时候设置断点
这样就可以看到函数调用栈,从而帮助我们更加精确的定位程序泄露的位置(调用栈可是个好玩意)。
个人感觉这种方式虽然要手动的修改代码,但其功能却比前两个工具的有效,因为能够在程序运行的时候查看调用栈,这就意味着能够调试程序。
展示结果如下图所示(自动在第150次申请堆空间处中断):
二.内存溢出
本篇最想分享的就是内存溢出的调试方法,内存溢出能够导致程序异常,而且这种异常使程序员难以下手。
2.1 内存溢出导致的异常症状
(1)内存异常经常产生的程序报错,如下图所示:
(2)有可能调试的时候不错,运行的时候出错,而且随机出现,这绝对让人很头疼的问题。
(3)庆幸的是,如果编译后的debug程序,直接运行后,如果出错,可以选择调试程序(如下图所示);
千万别以为麻烦就此可以解决了,进入调试状态后,发现出错的地方根本代码没有任何问题,可见内存溢出是个多么令人讨厌的家伙;
2.2 解决方法
虽然他是那么可恶,但也不要忘了是程序员自己一手创建了出来的。也不要灰心,困难总是有方法去解决的。
(1)等到生病的时候,再去看病,或许已经晚了;最好是提前做好预防准备;
A) 比如在程序中多使用strcpy_s、memcpy_s等具有缓冲区大小检查的函数,去取代strcpy、memcpy等;
B)给工程设置编译选项/WX开启(“将警告视为错误”),严格要求自己,这样很可能避免了不少潜在的bug;
对自己的代码做好单元测试
(2)如果出现了这种难以查找的错误,可以从程序源码着手,查看一些和内存操作相关的函数,比如strcpy、memcpy等。
本人曾经在项目中就遇到用一个项目组成员在使用,strcpy拷贝一个字符串到一个空间不够的内存,从而导致程序异常:
//拷贝字符串,并且返回新的字符串地址
char * string_copy(const char *source)
int string_
string_len = strlen(source);
if(source == NULL)
p_string = (char *)malloc(2*sizeof(char));
strcpy(p_string, "");
{ //这里错误 string_len+1
p_string = (char *)malloc((string_len)*sizeof(char));
strcpy(p_string, source);
静态地去检查代码方法比较慢,而且不适用于大工程。
(3)检查工具
幸运的是本人接触了一个代码量较大的工程,不幸的是发生了内存溢出问题,而导致程序异常。而且出现的症状,就是调试不错,运行出错,
而且随机出现,并且内存异常的代码处,代码没有任何问题。这个问题纠结了至少一个月,病极乱投医,但找了一些工具大多用于检查内存泄露的。
最终确定了两个工具:
A)BoudsChecker,除了能够检查内存泄露,也能检查内存溢出问题;可惜的是没有找到Win7 下支持VS2005的破解版本
B)AppVerifier,
corruption
没有更多推荐了,
不良信息举报
举报内容:
内存泄露、内存溢出以及解决方法
举报原因:
原文地址:
原因补充:
最多只允许输入30个字
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!主题 : swift3.0帮忙看下,内存泄漏啦
级别: 新手上路
可可豆: 31 CB
威望: 31 点
在线时间: 274(时)
发自: Web Page
来源于&&分类
swift3.0帮忙看下,内存泄漏啦&&&
swift3.0内存测试 发现好几处内存回收错误 发图真不方便
图片:屏幕快照
下午6.56.59.png
图片:屏幕快照
下午6.57.24.png
级别: 新手上路
可可豆: 31 CB
威望: 31 点
在线时间: 274(时)
发自: Web Page
swift2.3时&&用xcode 工具 测试 没有 内存泄漏情况,&&前些天 修改代码到 3.0&&今天无聊 测试一下, 发现很多地方莫名其妙的内存泄漏
级别: 骑士
可可豆: 380 CB
威望: 370 点
在线时间: 773(时)
发自: Web Page
请先check一下代码里面是否含有循环引用之类的情况……之前没检查出来可能是内存泄漏工具还不是很完善……而这次能检测出来也不排除内存泄漏检测工具bug了……一切皆有可能~
级别: 新手上路
可可豆: 31 CB
威望: 31 点
在线时间: 274(时)
发自: Web Page
回 2楼(u_r_sb) 的帖子
都加上了 【weak self】
关注本帖(如果有新回复会站内信通知您)
发帖、回帖都会得到可观的积分奖励。
按"Ctrl+Enter"直接提交
关注CocoaChina
关注微信 每日推荐
扫一扫 关注CVP公众号
扫一扫 浏览移动版&nbsp>&nbsp
&nbsp>&nbsp
&nbsp>&nbsp
RxSwift 内存泄漏与资源释放/管理
摘要:前几天看了美团的ReactiveCocoa中潜在的内存泄漏及解决方案,我也来试着写一下在使用RxSwift中可能存在的内存泄漏问题,以及对应的解决方案,同时讨论在RxSwift下如何进行资源的管理与释放,即解释DisposeBag。考虑到现在自己很喜欢RxSwift中Swift3.0分支的API,本文示例代码均基于Swift3.0版本内存泄漏未调用onCompleted在Rx中,对一个Model进行监听是件非常麻烦的事情,但我们还是先试着写了一下。classMTModel:N
前几天看了美团的 ReactiveCocoa 中潜在的内存泄漏及解决方案 ,我也来试着写一下在使用 RxSwift 中可能存在的内存泄漏问题,以及对应的解决方案,同时讨论在 RxSwift 下如何进行资源的管理与释放,即解释 DisposeBag 。
考虑到现在自己很喜欢 RxSwift 中 Swift 3.0 分支的 API ,本文示例代码均基于 Swift 3.0 版本
内存泄漏 未调用 onCompleted
在 Rx 中,对一个 Model 进行监听是件非常麻烦的事情,但我们还是先试着写了一下。 class MTModel: NSObject { dynamic var title: String init(_ title: String) { self.title = title }}
此时建立一个 Model ,为了支持 KVO ,需要继承 NSObject 同时添加 dynamic 标记(或者添加 @objc 标记)。
Observable.just(model) .flatMap { $0.rx.observe(String.self, &title&) } .subscribe(onNext: { value in if let value = value { print(&Title is /(value).&) } }, onCompleted: { print(&Completed&) }, onDisposed: { print(&Disposed&) })model .rx .deallocated .subscribe(onNext: { print(&Model deallocated&) })model.title = &111&model.title = &222&
首先对应的 ViewController 已经释放了,这点和 ReactiveCocoa 2.5 不同,KVO 观察时,持有者并非当前的 ViewController 。但这里尴尬的是打印结果。 Title is title.Title is 111.Title is 222.
可以看到控制台并没有打印 Completed 和 Disposed , 整个事件流并没有释放,同时 model 也没有被释放(即没有打印 Model deallocated )。
这是正常的,因为一个 KVO ,即 rx.observe 是一个无限序列,本身自己并不会发射 Completed 。
有两种常用的方式解决上述问题。 .takeUntil(rx.deallocated) .flatMap { $0.rx.observe(String.self, &title&) }.takeUntil(rx.deallocated)
在之前的 flatMap 后面添加 .takeUntil(rx.deallocated) 即可。
此时打印结果为。 Title is title.Title is 111.Title is 222.CompletedDisposedModel deallocated
相关的资源都已经释放。 DisposeBag
此外我们还可以通过添加 DisposeBag 解决该问题。
首先需要 ViewController 持有一个 disposeBag 。
let disposeBag = DisposeBag()
最后在订阅的结尾添加 .addDisposableTo(self.disposeBag) ,完整代码如下。
Observable.just(model) .flatMap { $0.rx.observe(String.self, &title&) } .subscribe(onNext: { value in if let value = value { print(&Title is /(value).&) } }, onCompleted: { print(&Completed&) }, onDisposed: { print(&Disposed&) }) .addDisposableTo(self.disposeBag)
打印结果。 Title is title.Title is 111.Title is 222.Model deallocatedDisposed
可以看到这里虽然没有打印 Completed ,但相关资源已经释放了。
没有打印 Completed 是正常的,因为整个事件流并没有人发射 Completed 。 当然,如果你认为 just 方法中发射了 Completed ,那也对,只是 flatMap 后的 Observable 是个无限的序列,自然也就轮不到 Completed 的传递了。
关于选择 DisposeBag 优于 takeUntil(rx.deallocated) 的讨论,我们将放到文章的第二部分,这里我们继续讨论内存泄漏问题。
这个就不需要多解释了,RxSwift 不像 ReactiveCocoa 2.5 版本使用了各种宏的黑魔法,所以出现循环引用一般都是写了 self 等情况。
原则上, self 应当只出现在 subscribe 中。
这是一个在 Swift 中比较有意思的事情。 func foo(bar: Int) { print(bar)}var foo : (bar: Int) -& () { return { bar in print(bar) }}
二者几乎是一样的。此时代码可以写成这个样子。 Observable.just(1) .map { $0 + 1 } .subscribe(onNext: foo) .addDisposableTo(disposeBag)
所以才有这样一段有趣的代码。 tableView .rx .itemSelected .map { (at: $0, animated: true) } .subscribe(onNext: tableView.deselectRow) .addDisposableTo(disposeBag)
然而,对于 foo 的那部分代码是可能存在循环引用的, foo 选择 func 实现时,会存在不知所措的循环引用。
这个暂时表示无解了。Orz 资源释放/管理
对于资源释放问题,最佳实践就是采用 DisposeBag 。
DisposeBag 会在其析构时释放持有的订阅者们,同时调用订阅者的 dispose 释放相关资源。
public final class DisposeBag: DisposeBase { // ... private func dispose() { let oldDisposables = _dispose() for disposable in oldDisposables { disposable.dispose() } } deinit { dispose() }}
在创建每个 Observable 时,我们都可以在 dispose 时释放一些资源。比如 RxCocoa 中的网络请求,在释放资源时会 cancel 对应的 task Disposables.create(with: task.cancel) 。
public func response(_ request: URLRequest) -& Observable&(Data, HTTPURLResponse)& { return Observable.create { observer in let task = self.base.dataTask(with: request) { (data, response, error) in // ... observer.on(.next(data, httpResponse)) observer.on(.completed) } let t = task t.resume() return Disposables.create(with: task.cancel) }}
但需要注意的是,一般情况我们是 不需要手动管理 DisposeBag 。
来看下面这部分代码。 private func reloadData() { if disposable != nil { disposable?.dispose() disposable = nil } disposable = viewModel .updateData() .doOnError { [weak self] error in JLToast.makeText(&网络数据异常,请下拉重试!&).show() self?.refresher.stopLoad() } .doOnCompleted { [weak self] in self?.refresher.stopLoad() } .subscribe()}
不可以,这不可以,这样使用反而让代码维护更辛苦了,明明就是想刷新一下数据,却有 40% 的代码处理 disposable 了。项目逻辑复杂时,就会有一大堆 disposable ,这样的话不如使用 PromiseKit 会更简洁一些。
这段代码是从富强大大的 Swift 实践初探 摘来的代码,Orz 但愿我不会被打,拍个马屁,这篇文章对于 RxSwift 中的一些概念解释的还是很清晰的。补充,引入第三方框架,Carthage 可能是更好的选择。
当然上面的代码也可能会被写成这个样子。 private func reloadData() { disposeBag = DisposeBag() viewModel .updateData() .doOnError { [weak self] error in JLToast.makeText(&网络数据异常,请下拉重试!&).show() self?.refresher.stopLoad() } .doOnCompleted { [weak self] in self?.refresher.stopLoad() } .subscribe() .addDisposableTo(disposeBag)}
此外上面这部分代码对于 doOn 的使用是比较不合理的。
我会在将来的文章中提到一些 doOn 的使用场景。
注,关于 RxSwift 和 PromiseKit 的区别,我将会在 RxSwift vs PromiseKit 文章中进行探讨,我将解释为什么 PromiseKit 只是一个异步处理库,为什么 RxSwift 不适合仅用来处理异步。
正确理解 flatMap 使用 RxSwift 后,基本上就没有方法调用一说了。如果有,这基本不 Rx 。 逻辑源头
仍然以上面 reloadData 为例。 一定有一个/多个 reloadData 的时机。 比如,点击 Button ,下拉等。这里逻辑源头就是点击 Button 而非 reloadData 。
我们先以点击 Button 为例,画个图描述问题。
而原代码是
所以比较合理的代码写法应当是指出什么引起 reloadData ,通过链式调用将触发原因指出来。本例中通过 Button 点击触发数据更新。
button .rx .tap .map { URL(string: &http://httpbin/org&)! } .flatMap(URLSession.shared.rx.JSON) .subscribe { event in switch event { // ... } } .addDisposableTo(disposeBag)
这段代码简单的描述了上面图中的逻辑,呈现一种流式的代码。我们可以将代码写成上面的样子,完全是多亏了 flatMap 这个操作符,通过返回一个 Observable 确保不论是异步执行代码还是同步代码,都能以链式的方式完成代码的书写。
此外 flatMap 还有两个兄弟方法, flatMapFirst flatMapLatest ,比如在网络请求未完成时,再次点击了 Button , flatMapFirst 会忽略第二次点击 Button 的事件,不会进行网络请求;而 flatMapLatest 会取消第一次的网络请求,以第二次的网络请求覆盖掉。
如果有多个触发网络请求的情况,我们可以使用诸如 merge zip combineLatest 等操作符完成更加复杂的业务逻辑。这一点,本文就不在这里赘述了,这不是本文的重点。
以上是的内容,更多
的内容,请您使用右上方搜索功能获取相关信息。
若你要投稿、删除文章请联系邮箱:zixun-group@service.aliyun.com,工作人员会在五个工作日内给你回复。
云服务器 ECS
可弹性伸缩、安全稳定、简单易用
&40.8元/月起
预测未发生的攻击
&24元/月起
为您提供0门槛上云实践机会
你可能还喜欢
你可能感兴趣
阿里云教程中心为您免费提供
RxSwift 内存泄漏与资源释放/管理相关信息,包括
的信息,所有RxSwift 内存泄漏与资源释放/管理相关内容均不代表阿里云的意见!投稿删除文章请联系邮箱:zixun-group@service.aliyun.com,工作人员会在五个工作日内答复
售前咨询热线
支持与服务
资源和社区
关注阿里云
International没有更多推荐了,
不良信息举报
举报内容:
iOS开发那些事--性能优化–内存泄露问题的解决
举报原因:
原文地址:
原因补充:
最多只允许输入30个字
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!

我要回帖

更多关于 swift 获取mac地址 的文章

 

随机推荐