【iOS】内存泄漏检查及原因分析
目录
- 为什么要检测内存泄漏?
- 什么是内存泄漏?
- 内存泄漏排查方法
- 1. 使用Zombie Objects
- 2. 静态分析
- 3. 动态分析方法
- 定位修改
- Leaks界面分析
- Call Tree的四个选项:
- 内存泄漏原因分析
- 1. Leaked Memory:应用程序未引用的、不能再次使用或释放的内存。
- 2. Abandoned Memory: 内存仍被应用程序所引用,没有任何有用的用途。
- 3. Cached Memory:内存仍然由应用程序引用,可以再次使用以获得更好的性能。
前言:
- 内存溢出(out of memory):是指程序在申请内存时,没有足够的内存空间供其使用,出现
out of memory
。通俗理解就是内存不够,通常在运行大型软件或游戏时,软件或游戏所需要的内存远远超出了你主机内安装的内存所承受大小,就叫内存溢出。- 内存泄露( memory leak):是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
为什么要检测内存泄漏?
迅速膨胀的内存可以很快让程序毙命,所以要多加防范。即使有 ARC(自动引用计数)内存管理机制,但在现实中对象之间引用复杂,循环引用导致的内存泄漏仍然难以避免,所以关键时刻还要自力更生。分析内存泄露不能把所有的内存泄露查出来,有的内存泄露是在运行时,用户操作时才产生的。
什么是内存泄漏?
内存泄漏指的是一块内存被分配后不再使用,但是没有被程序正确释放回系统,从而导致该内存继续占用在程序中,无法被其它任务使用。
这通常发生在使用了动态内存分配但未及时或正确释放,或者由于编程逻辑错误导致。如果不加以管理,会导致程序消耗过多的内存,甚至导致应用程序崩溃。
比如下MRC中如下代码会造成泄漏:
NSString* string = [[NSString alloc] init];
...
// [string release]; //ARC下,编译器自动添加此代码
但由于ARC机制,编译器会在适当的时机帮我们加上release
代码,避免了内存泄漏。不过即使在ARC中也有肯能因对象不释放而引起内存泄漏,比如使用CF框架下的对象而没有做CFRelease
操作。
虽然string
所占的内存很小可以忽略不计,但也是有安全隐患的,就像前言所述,代码中这里泄漏一点内存,那里又泄漏一点内存,反反复复,内存总会有用尽的那一刻。
毕竟系统本身内存有限,分配给每个App的内存更加有限,当系统内存慢慢不足时,我们的App会变得越来越卡顿。
当系统内存告急时,App中首先会收到didRecieveWarning
提醒,如果我们不第一时间采取措施释放内存,那么系统就会把我们的App Kill掉,所以我们应该重视内存泄漏问题。
didRecieveWarning
调用流程看这篇文章:【iOS】didReceiveMemoryWarning实例方法
内存泄漏排查方法
1. 使用Zombie Objects
有时候我们会收到EXC_BASD_ACCESS
错误提示,但没能跳到具体的出错代码行,此时可以启用Zombie Objects
功能,来寻找那些已被释放的对象。
进入edit Scheme:
选中僵尸对象选项:
按照以上步骤开启Zombies Objects
,而后Memory查看器变为disable:
系统在即将回收对象时,如果发现通过环境变量启用了僵尸对象功能,那么还将执行一个附加步骤,即把对象转化为僵尸对象,而不彻底回收。
测试代码:
void PrintClassInfo(id obj) {Class cls = object_getClass(obj);Class superCls = class_getSuperclass(cls);NSLog(@"=== %s : %s ===", class_getName(cls), class_getName(superCls));
}- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.UIView* view = [[UIView alloc] init];NSLog(@"Before release:");PrintClassInfo(view);[view release];NSLog(@"After release:");PrintClassInfo(view);
}
2. 静态分析
打开Xcode项目,并点击Product->Analyze:
静态内存泄漏分析如下:
静态分析方法能发现大部分的问题,但是只能是静态分析结果,有一些并不准确,还有一些动态分配内存的情形并没有进行分析。所以仅仅使用静态内存泄漏分析得到的结果并不是非常可靠,如果需要,我们需要将对项目进行更为完善的内存泄漏分析和排查。那就需要用到我们下面要介绍的动态内存泄漏分析方法Instruments中的Leaks方法进行排查。
3. 动态分析方法
打开Xcode项目,点击Product->Profile:
选择Leaks,这时项目也在模拟器或真机上运行起来了:
或者直接在自己的项目中运行程序,选中Memory点击右上角的Profile in instruments:
都可以进入下面的页面:
由于 Leaks 是动态监测,所以我们需要手动操作 APP,进行测试,一边操作 APP,一边观察 Leaks 的变化,在 暂停按钮 的右边 我们可以选择正在 运行的程序 & 选择设备 & App, 之后点击 红点 Record(红色圆圈按钮)运行。
观察,如果发现在 Leaks 里面有一个 红色X,这说明了我们的 APP 存在内存泄露。
就像这样
点击暂停,点击其中一个,然后我们开始分析。
定位修改
此时选中有红色叉的 Leaks,下面有个Leaks 字方格,点开,选中 Call Tree。
接着就是最关键的一步,在这个界面的右下角有若干选框,选中Invert Call Tree(从上到下跟踪堆栈信息) 和 Hide System Libraries(表示隐藏系统的函数)
在详情面板选中显示的若干条中的一条,双击,会自动跳到内存泄露代码处,然后点击右上角 Xcode 图标进行修改。
Leaks界面分析
Leaks 启动后会开始录制,随着对模拟器运行的 App 的操作,可以在 Leaks 中查看内存占用的情况。
Leaks顶部分为两栏:Allocations 和 Leaks,右侧的曲线代表内存分配和内存泄漏曲线。
Call Tree的四个选项:
- Separate By Thread: 线程分离,只有这样才能在调用路径中能够清晰看到占用CPU最大的线程.每个线程应该分开考虑。只有这样你才能揪出那些大量占用CPU的"重"线程,按线程分开做分析,这样更容易揪出那些吃资源的问题线程。特别是对于主线程,它要处理和渲染所有的接口数据,一旦受到阻塞,程序必然卡顿或停止响应。
- Invert Call Tree: 从上到下跟踪堆栈信息.这个选项可以快捷的看到方法调用路径最深方法占用CPU耗时(这意味着你看到的表中的方法,将已从第0帧开始取样,这通常你是想要的,只有这样你才能看到CPU中话费时间最深的方法),比如FuncA{FunB{FunC}},勾选后堆栈以C->B->A把调用层级最深的C显示最外面.反向输出调用树。把调用层级最深的方法显示在最上面,更容易找到最耗时的操作。
- 表示隐藏系统的函数,调用这个就更有用了,勾选后耗时调用路径只会显示app耗时的代码,性能分析普遍我们都比较关系自己代码的耗时而不是系统的.基本是必选项.注意有些代码耗时也会纳入系统层级,可以进行勾选前后前后对执行路径进行比对会非常有用.因为通常你只关心cpu花在自己代码上的时间不是系统上的,隐藏系统库文件。过滤掉各种系统调用,只显示自己的代码调用。隐藏缺失符号。如果 dSYM 文件或其他系统架构缺失,列表中会出现很多奇怪的十六进制的数值,用此选项把这些干扰元素屏蔽掉,让列表回归清爽。
- 递归函数, 每个堆栈跟踪一个条目,拼合递归。将同一递归函数产生的多条堆栈(因为递归函数会调用自己)合并为一条。
内存泄漏原因分析
在目前主要以ARC进行内存管理的开发模式,导致内存泄漏的根本原因是代码总存在循环引用,从而导致一些内存无法释放,这就会导致dealloc方法无法被调用。
开启了ARC并不是就不会存在内存问题,苹果有句名言:ARC is only for NSObject
。
使用ARC的项目,一般内存泄漏都是 malloc、自定义结构、资源引起的,多注意这些地方进行分析。
注:如果你的项目使用了ARC,随着你的操作,不断开启或关闭视图,内存可能持续上升,但这不一定表示存在内存泄漏,ARC释放的时机是不固定的。
引起内存泄漏的几种原因:
1. Leaked Memory:应用程序未引用的、不能再次使用或释放的内存。
-
在OC的ARC机制下,使用CF或CG对象时,忘记手动调用
CFRelease
或CGRelease
。CGImageRef* imageRef = CGImageCreateWithImageInRect(someImage, someRect); // ... // CGImageRelease(imageRef); // 释放内存
-
for循环中超多次加载比较占内存的对象:频繁创建大量占用内存的对象,如果不使用
@autorelease
,会导致内存无法及时释放。for (int i = 0; i < 1000; ++i) {@autoreleasepool {UIImage* image = [UIImage imageNamed: @"largeImage"];// ...} }
2. Abandoned Memory: 内存仍被应用程序所引用,没有任何有用的用途。
大多是OC对象、block、timer、delegate等循环引用问题,造成引用计数一直不为零。
-
OC对象循环引用:
@interface Person : NSObject @property (nonatomic, strong)Person* friends; @end@implementation Person - (void)dealloc {NSLog(@"Person 对象被释放"); } @endint main(int argc, const char * argv[]) {@autoreleasepool {Person* person1 = [[Person alloc] init];Person* person2 = [[Person alloc] init];person1.friends = person2;person2.friends = person1;}return 0; }
person1和person2互相引用,形成了循环(强)引用,这两个对象的引用计数不会降为0,
dealloc
方法并没有被执行。
解决办法就是使用弱引用打破循环:@property (nonatomic, weak)Person* friends
。
- Block循环引用:@interface MyClass : NSObject @property (nonatomic, strong) void (^myBlock)(void); - (void)setupBlock; @end@implementation MyClass- (void)setupBlock {// __weak typeof(self) weakSelf = self;self.myBlock = ^{// __strong typeof(weakSelf) strongSelf = weakSelf;NSLog(@"%@", self); // 造成强引用循环// if (strongSelf) {// NSLog(@"%@", strongSelf);// }}; }@endMyClass *obj = [[MyClass alloc] init]; [obj setupBlock];
如果没有注释掉的那段代码,
self.myBlock
对self
产生了强引用,导致self
的引用计数永远不会为零,从而引起循环引用。
-
Timer循环引用:
@interface MyClass : NSObject @property (nonatomic, strong) NSTimer *timer; @end@implementation MyClass - (void)startTimer {// __weak typeof(self) weakSelf = self;self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerFired) userInfo:nil repeats:YES]; }- (void)timerFired {// Timer fired actions } @end
如果没有注释掉的那段代码,
NSTimer
对self
保持强引用(target: self
增加了ViewController的引用计数,如果不进行[timer invalidate];
,就别想调用dealloc
了),而self
对NSTimer
也保持强引用,形成循环引用。
timer
属性也最好设置为弱引用(weak)。 -
Delegate引起的循环引用:
@interface MyObject : NSObject @property (nonatomic, strong)id<MyDelegate> delegate; @end@interface MyViewController : UIViewController <MyDelegate> @property (nonatomic, strong) MyObject *myObject; @end@implementation MyViewController - (void)viewDidLoad {[super viewDidLoad];self.myObject.delegate = self; } @end
与Timer同理,
myObject
对delegate
使用强引用,delegate
又对myObject
保持强引用,形成循环引用。
解决方案是使用弱引用:@property (nonatomic, weak)id<MyDelegate> delegate;
。 -
ViewController的子视图对self的持有
我们有时候需要在子视图或者某个cell中点击跳转等操作,需要在子视图或cell中持有当前的ViewController对象,这样跳转之后的back键才能直接返回该页面,同时也不销毁当前ViewController。此时,你就要注意在子视图或者cell中对当前页面的持有对象不能是强引用,尽量assign或者weak,否则会造成循环引用,内存无法释放。
3. Cached Memory:内存仍然由应用程序引用,可以再次使用以获得更好的性能。
为了快速访问而存储起来的对象。
以缓存图片提高性能为例:
@class UIImage;
@interface ImageCache : NSObject
@property (nonatomic, strong) NSMutableDictionary* cache;
+ (instancetype)sharedInstance;
- (UIImage *)imageForKey:(NSString *)key;
- (void)setImage:(UIImage *)image forKey:(NSString *)key;
@end// ImageCache.m
#import "ImageCache.h"
#import "UIKit/UIImage.h"@implementation ImageCache+ (nonnull instancetype)sharedInstance {static ImageCache *sharedInstance = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{sharedInstance = [[self alloc] init];sharedInstance.cache = [NSMutableDictionary dictionary];});return sharedInstance;
}- (void)setImage:(nonnull UIImage *)image forKey:(nonnull NSString *)key {self.cache[key] = image;
}- (nonnull UIImage *)imageForKey:(nonnull NSString *)key {return self.cache[key];
}@end// 使用缓存
UIImage* image = [UIImage imageNamed: @"example.png"];
[[ImageCache sharedInstance] setImage: image forKey: @"example"];// 之后访问缓存的图片
UIImage* cachedImage = [[ImageCache sharedInstance] imageForKey: @"example"];```
示例中,图片被缓存以便快速访问,从而提高性能。缓存图片使用的内存不是泄漏,因为这戏内存是有意保留以供将来使用的。
相关文章:
【iOS】内存泄漏检查及原因分析
目录 为什么要检测内存泄漏?什么是内存泄漏?内存泄漏排查方法1. 使用Zombie Objects2. 静态分析3. 动态分析方法定位修改Leaks界面分析Call Tree的四个选项: 内存泄漏原因分析1. Leaked Memory:应用程序未引用的、不能再次使用或释…...
“深入探讨Java中的对象拷贝:浅拷贝与深拷贝的差异与应用“
前言:在Java编程中,深拷贝(Deep Copy)与浅拷贝(Shallow Copy)是两个非常重要的概念。它们涉及到对象在内存中的复制方式,对于理解对象的引用、内存管理以及数据安全都至关重要。 ✨✨✨这里是秋…...
Docker 进入指定容器内部(以Mysql为例)
文章目录 一、启动容器二、查看容器是否启动三、进入容器内部 一、启动容器 这个就不多说了 直接docker run… 二、查看容器是否启动 查看正在运行的容器 docker ps查看所有的容器 docker ps -a结果如下图所示: 三、进入容器内部 通过CONTAINER ID进入到容器…...
计算机网络-数制转换与子网划分
目录 一、了解数制 1、计算机的数制 2、二进制 3、八进制 4、十进制 5、十六进制 二、数制转换 1、二进制转十进制 2、八进制转十进制 3、十六进制转十进制 4、十进制转二进制 5、十进制转八进制 6、十进制转十六进制 三、子网划分 1、IP地址定义 2、IP的两种协…...
【ssh命令】ssh登录远程服务器
命令格式:ssh 用户名主机IP # 使用非默认端口: -p 端口号 ssh changxianrui192.168.100.100 -p 1022 # 使用默认端口 22 ssh changxianrui192.168.100.100 然后输入密码,就可以登录进去了。...
【区块链】truffle测试
配置区块链网络 启动Ganache软件 使用VScode打开项目的wordspace 配置对外访问的RPC接口为7545,配置项目的truffle-config.js实现与新建Workspace的连接。 创建项目 创建一个新的目录 mkdir MetaCoin cd MetaCoin下载metacoin盒子 truffle unbox metacoincontra…...
【AIGC调研系列】chatTTS与GPT-SoVITS的对比优劣势
ChatTTS和GPT-SoVITS都是在文本转语音(TTS)领域的重要开源项目,但它们各自有不同的优势和劣势。 ChatTTS 优点: 多语言支持:ChatTTS支持中英文,并且能够生成高质量、自然流畅的对话语音[4][10][13]。细粒…...
LLVM Cpu0 新后端10
想好好熟悉一下llvm开发一个新后端都要干什么,于是参考了老师的系列文章: LLVM 后端实践笔记 代码在这里(还没来得及准备,先用网盘暂存一下): 链接: https://pan.baidu.com/s/1yLAtXs9XwtyEzYSlDCSlqw?…...
k8s面试题大全,保姆级的攻略哦(二)
目录 三十六、pod的定义中有个command和args参数,这两个参数不会和docker镜像的entrypointc冲突吗? 三十七、标签及标签选择器是什么,如何使用? 三十八、service是如何与pod关联的? 三十九、service的域名解析格式…...
Mysql:通过一张表里的父子级,递归查询并且分组分级
递归函数WITH RECURSIVE语法 WITH RECURSIVE cte_name (column_list) AS (SELECT initial_query_resultUNION [ALL]SELECT recursive_queryFROM cte_nameWHERE condition ) SELECT * FROM cte_name; WITH RECURSIVE 关键字:表示要使用递归查询的方式处理数据。 c…...
数据结构之排序算法
目录 1. 插入排序 1.1.1 直接插入排序代码实现 1.1.2 直接插入排序的特性总结 1.2.1 希尔排序的实现 1.2.2 希尔排序的特性总结 2. 选择排序 2.1.1 选择排序 2.1.2 选择排序特性 2.2.1 堆排序 2.2.2 堆排序特性 3. 交换排序 3.1.1 冒泡排序 3.1.2 冒泡排序的特性 …...
移动安全赋能化工能源行业智慧转型
随着我国能源化工企业的不断发展,化工厂中经常存在火灾爆炸的危险,特别是生产场所,约有80%以上生产场所区域存在爆炸性物质。而目前我国化工危险场所移动通信设备的普及率高,但是对移动通信设备的安全防护却有所忽视,包…...
今天是放假带娃的一天
端午节放假第一天 早上5点半宝宝就咔咔乱叫了,几乎每天都这个点醒,准时的很,估计他是个勤奋的娃吧,要早起锻炼婴语,哈哈 醒来后做饭、洗锅、洗宝宝的衣服、给他吃D3,喂200ml奶粉、给他洗澡、哄睡࿰…...
linux Ubuntu安装samba服务器与SSH远程登录
目录 1,下载安装包 2,添加服务器 3,修改服务器配置 3.1 备份配置文件 3.2 修改配置 4,开启samba服务器 5,开关电脑与服务器设置 6, SSH远程登录 1,下载samba服务器安装包 sudo apt in…...
纳什均衡:博弈论中的运作方式、示例以及囚徒困境
文章目录 一、说明二、什么是纳什均衡?2.1 基本概念2.2 关键要点 三、理解纳什均衡四、纳什均衡与主导策略五、纳什均衡的例子六、囚徒困境七、如何原理和应用7.1 博弈论中的纳什均衡是什么?7.2 如何找到纳什均衡?7.3 为什么纳什均衡很重要&a…...
Linux之进程信号详解【上】
🌎 Linux信号详解 文章目录: Linux信号详解 信号入门 技术应用角度的信号 信号及信号的产生 信号的概念 信号的处理方式 信号的产生方式 键盘产生信号 系统调用产生信号 软件…...
【Spring Cloud】Eureka详细介绍及底层原理解析
目录 底层原理详解 1. 服务注册与发现 2. 心跳机制 3. 服务剔除与自我保护机制 Eureka Server 核心组件 Eureka Client 核心组件 使用场景 结语 Eureka 是 Netflix 开源的一款服务发现框架,用于构建分布式系统中的服务注册与发现。 它包含两个核心组件&…...
【清华大学】《自然语言处理》(刘知远)课程笔记 ——NLP Basics
自然语言处理基础(Natural Language Processing Basics, NLP Basics) 自然语言处理( Natural Language Processing, NLP)是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。自然语言…...
代码随想录 | Day17 | 二叉树:二叉树的最大深度最小深度
代码随想录 | Day17 | 二叉树:二叉树的最大深度&&最小深度 主要学习内容: 利用前序后序层序求解二叉树深度问题 其中穿插回溯法 104.二叉树的最大深度 104. 二叉树的最大深度 - 力扣(LeetCode) 递归遍历 后序遍历 …...
【Linux】Socket编程基础
文章目录 字节序字节序转化函数 套接字socket通用结构体通信类型名空间套接字函数socket():创建套接字bind()函数:绑定服务器套接字与其地址、端口listen()函数:侦听客户连接connect():连接服务器套接字accept()函数:服…...
关于stm32的软件复位
使用软件复位的目的: 软件复位并不会擦除存储器中的数据,它只是将处理器恢复到复位状态,即中断使能位被清除,系统寄存器被重置,但RAM和Flash存储器中的数据保持不变。 STM32软件复位(基于库文件V3.5) ,对…...
规范系统运维:系统性能监控与优化的重要性与实践
在当今这个高度信息化的时代,企业的IT系统运维工作显得尤为关键。其中,系统性能监控和优化是运维工作中不可或缺的一环。本文旨在探讨规范系统运维中系统性能监控与优化的重要性,并分享一些实践经验和策略。 一、系统性能监控与优化的重要性…...
用python编撰一个电脑清理程序
自制一个电脑清理程序,有啥用呢?在电脑不装有清理软件的时候,可以解决自己电脑内存不足的情况。 1、设想需要删除指定文件夹中的临时文件和缓存文件。以下是代码。 import os import shutil def clean_folder(folder_path): for root,…...
2024年【天津市安全员C证】免费试题及天津市安全员C证试题及解析
题库来源:安全生产模拟考试一点通公众号小程序 天津市安全员C证免费试题是安全生产模拟考试一点通生成的,天津市安全员C证证模拟考试题库是根据天津市安全员C证最新版教材汇编出天津市安全员C证仿真模拟考试。2024年【天津市安全员C证】免费试题及天津市…...
【Python数据挖掘实战案例】机器学习LightGBM算法原理、特点、应用---基于鸢尾花iris数据集分类实战
一、引言 1、简要介绍数据挖掘的重要性和应用 在数字化时代,数据已经成为企业和社会决策的重要依据。数据挖掘作为一门交叉学科,结合了统计学、机器学习、数据库技术和可视化等多个领域的知识,旨在从海量数据中提取有价值的信息,…...
使用LabVIEW进行大数据数组操作的优化方法
针对大数据量数组操作,传统的内存处理方法可能导致内存不足。通过LabVIEW的图像批处理技术,可以有效地进行大数据数组操作,包括分块处理、并行处理和内存优化等。这种方法能显著提高处理效率和系统稳定性。 图像批处理的优势 内存优化&#…...
【Linux】(五)—— SSH远程登录和XShell使用
SSH Linux中的SSH(Secure Shell)是一个强大的网络协议,用于在不安全的网络环境中提供安全的远程登录和资料拷贝等其他网络服务。以下是有关Linux中SSH的关键点和操作指南: SSH的基础概念 安全性:SSH通过对所有传输的…...
前端怎么实现跨域请求?
前端实现跨域请求(Cross-Origin Resource Sharing, CORS)通常涉及到后端服务器的配置,因为浏览器的同源策略(Same-Origin Policy)会阻止前端代码直接发起跨域请求。然而,有几种方法可以在前端和后端的配合下…...
sqlmap直接嗦 dnslog注入 sqllibs第8关
dnslog注入是解决注入的时候没有回显的情况,通过dns外带来进行得到我们想要的数据。 我们是用了dns解析的时候会留下记录,这时候就可以看见我们想要的内容。 这个时候我们还要了解unc路径以及一个函数load_file()以及concat来进行注入。看看我的笔记 unc…...
数据结构笔记 3 串 数组 广义表
以下了解即可,暂时没发现有什么考点 参考: 【数据结构】——多维数组和广义表_数据结构loc-CSDN博客 相对应的题目: 他这个数组不是从0开始的,是从1开始的,所以为了配合公式要减1 下面这道题又不一样,它是…...
手游网站建设的宗旨/网站维护需要多长时间
2020年对华为来说,无疑是十分艰难的一年,通信设备与消费电子两大业务都受到了不小的冲击,令人担忧。但是,华为不仅挺过了2020年,还取得了一系列优异成绩,一次次证明着自己的实力。日前,华为又有…...
网站上的高清动态图怎么做的/百度推广在线客服
网上相当一部分博客如此描述内外部表的区别 创建表时:创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径, 不对数据的位置做任何改变。 删除表时:在删除表的时候ÿ…...
唐山seo设计网站/产品seo标题是什么
1.幅频特性、相频特性等属于是()。 A.电路性能的测量 B.特性曲线的测量 C.电能量的测量 D.电信号特性的测量 错误 正确答案:左边查询 学生答案:A 2.信号特性的测量指的是对频率、周期、时间、相位、调制系数、失真度等参量的测量。…...
建设工程合同范本 政府网站/100个商业经典案例
加载图像(用cv::imread)imread功能是加载图像文件成为一个Mat对象 其中第一个参数表示图像文件名称第二个参数 表示加载的图像是什么类型 支持常见的三个参数值IMREAD_UNCHANGE(<0)表示加载原图 不做任何改变IMREAD_GRAYSCALE(0)表示把原图作为灰度图像加载进来IMREAD_COLOR…...
政府门户网站建设的体现/怎么样建立自己的网站
Case when 的用法,简单Case函数 简单CASE表达式,使用表达式确定返回值. 语法: CASE search_expression WHEN expression1 THEN result1 WHEN expression2 THEN result2 ... WHEN expressionN THEN resultN ELSE default_result 搜索CASE表达式,使用条件确定返回值. 语法: CASE …...
重庆网站建设解决方案/网络优化的三个方法
我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版,欢迎购买。点击进入详情 文章目录如果你最近在使用git命令,你会发现输入github的账号密码会报错。比如:git push origin master当你输入github的帐号密码后…...