内存泄露监测

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

iOS 内存泄露监测
144  作者 谢谢生活 已关注
2017.05.19 17:38* 字数 4235 阅读 209评论 0喜欢 6
iOS可能存在的内存泄露:block 循环引用。当一个对象有一个block属性,而block属性又引用这个对象本身那么要造成循环引用。这个时候就用___weak声明下对象,用对象的弱引用指针。
头文件相互包含。那么先在.h文件用前向引用声明,@class(类名);然后在.m文件导入#import " AHMessageCell"(类头文件)
移除通知 [[NSNotificationCenter defaultCenter]removeObserver:self];、
移除NSTimer[_timer invalidate];_timer = nil;
移除观察者
//添加观察者[self addObserver:<#(nonnull NSObject *)#> forKeyPath:<#(nonnull NSString *)#> options:<#(NSKeyValueObservingOptions)#> context:<#(nullable void *)#>]
//移除观察者[self removeObserver:<#(nonnull NSObject *)#> forKeyPath:<#(nonnull NSString *)#>];
timer,观察者,通知的移除。一般的开发者都是放到dealloc中,但是这样不能保证一定能够移除成功。可以更加实际情况移除,可以在viewWillAppear中添加,viewWillDisappear中移除,也可以强制移除。iOS内存泄露测试:可以用xcode自带instrument工具,如:leaks、Analyze、allocation,也可以用第三方工具。一: leaks打开Xcode7自带的Instruments
打开Instruments
按上面操作,build成功后跳出Instruments工具,选择Leaks选项选择之后界面如下图:打开leaks
到这里之后,我们前期的准备工作做完啦,下面开始正式的测试!1.选中Xcode先把程序(command + R)运行起来2.再选中Xcode,按快捷键(command + control + i)运行起来,此时Leaks已经跑起来了3.由于Leaks是动态监测,所以我们需要手动操作APP,一边操作,一边观察Leaks的变化,当出现红色叉时,就监测到了内存泄露,点击右上角的第二个,进行暂停检测(也可继续检测,当多个时暂停,一次处理了多个).如图所示:4.下面就是定位修改了,此时选中有红色柱子的Leaks,下面有个"田"字方格,点开,选中Call Tree显示如下图界面找到内存泄露位置
5.下面就是最关键的一步,在这个界面的右下角有若干选框,选中Invert Call Tree 和Hide System Libraries,(红圈范围内)显示如下:监测回调函数
到这里就算基本完成啦,这里显示的就是内存泄露代码部分,那么现在还差一步:定位!6.选中显示的若干条中的一条,双击,会自动跳到内存泄露代码处,如图所示
查看回调函数
7.找到了内存泄露的地方,那么我们就可以修改即可。二:Analyze—静态分析顾名思义,静态分析不需要运行程序,就能检查到存在内存泄露的地方。使用方法:打开Xcode,command + shift + B;或者Xcode - Product - Analyze;
常见的三种泄露情形:
(1)创建了一个对象,但是并没有使用。Xcode提示信息: Value Stored to 'number' is never read 。翻译一下:存储在'number'里的值从未被读取过。
(2)创建了一个(指针可变的)对象,且初始化了,但是初始化的值一直没读取过。Xcode提示信息: Value Stored to 'str' during its initialization is never read
(3)调用了让某个对象引用计数加1的函数,但没有调用相应让其引用计数减1的函数。Xcode提示信息: Potential leak of an object stored into 'subImageRef' 。 翻译一下:subImageRef对象的内存单元有潜在的泄露风险。
贴上Demo代码:
/*** 情 形 一:创建了一个对象,但是并没有使用。* 提示信息:Value Stored to 'number' is never read* 翻译一下:存储在'number'里的值从未被读取过,*/
- (void)leakOne {NSString *str1 = [NSString string];NSNumber *number;number = @(str1.length);/*说我们没有读取过它,那就读取一下,比如打开下面这句代码,对它发送class消息,就不再会有这个提示了。当然最好的方法还是将有关number的代码都删掉,因为,你只对number赋值,又不使用,那干嘛创建出来呢。这是一个比较常见和典型的错误,也很容易检查出来*/// [number class];
}/*** 情 形 二:创建了一个(指针可变的)对象,且初始化了,但是初始化的值一直没读取过。* 提示信息:Value Stored to 'str' during its initialization is never read*/
- (void)leakTwo {NSString *str = [NSString string]; // 创建并初始化str,此时已经有一个内存单元保存str初始化的值// NSString *str; // 这样就内存不泄露,因为str是可变的,只需要先声明就行。// printf("str前 = %p\n",str);str = @"ceshi";             // str被改变了,指向了"ceshi"所在的地址,指针改变了,但之前保存初始化值的内存空间还未释放,保存str初始化值的内存单元泄露了。// printf("str后 = %p\n",str); // 指针改变了[str class];// 再举两个例子,同理NSArray *arr = [NSArray array];// printf("arr前 = %p\n",arr);// NSArray *arr;            // 这样就内存不泄露arr = @[@"1",@"2"];// printf("arr后 = %p\n",arr); // 指针改变了[arr class];CGRect rect = self.view.frame;// CGRect rect = CGRectZero; // 这样就内存不泄露rect = CGRectMake(0, 0, 0, 0);NSLog(@"rect = %@",NSStringFromCGRect(rect));
}/*** 情 形 三:调用了让某个对象引用计数加1的函数,但没有调用相应让其引用计数减1的函数。* 提示信息:Potential leak of an object stored into 'subImageRef'* 翻译一下:subImageRef对象的内存单元有潜在的泄露风险*/
- (void)leakThree {CGRect rect = CGRectMake(0, 0, 50, 50);UIImage *image;CGImageRef subImageRef = CGImageCreateWithImageInRect(image.CGImage, rect); // subImageRef 引用计数 + 1;UIImage* smallImage = [UIImage imageWithCGImage:subImageRef];// 应该调用对应的函数,让subImageRef的引用计数减1,就不会泄露了// CGImageRelease(subImageRef);[smallImage class];UIGraphicsEndImageContext();
}
监测结果:可能存在内存泄露的地方
三:allocation使用这个时候我们通过Allocation可以进行内存分析,将Xcode切换为Release状态,通过Product→Profile(Cmd+i)找到Allocations:
代开allocation
1.红色的按钮是表示停止和启动应用程序,不要理解成了暂停,Objective-C所有的对象都是在堆上分配的,记得勾选一下All Heap Allocations:
开始监测
2.点击All Heap Allocation,勾选Call Tree,同时不查看系统的函数库:
监测回调函数
3.具体方法占用的内存,可以逐级点开,效果如下:
内存占用
以上是常规的Allocations使用,关于第二张图的有框中的几个选项可以解释一下:
Separate by Thread: 每个线程应该分开考虑,考虑到应用程序中GCD的存在;
Invert Call Tree: 从上倒下跟踪堆栈,这意味着你看到的表中的方法,将已从第0帧开始取样,利用栈的先进后出的特性,我们可以在栈顶看到最近调用的函数;
Hide System Libraries: 勾选此项会显示app的代码,这是非常有用的;
Flatten Recursion: 递归函数, 每个堆栈跟踪一个条目;左侧有几个比较有用的选项:
All Objects Created
Created & Still Living
Created & Destroyed
内存监测
4.Allocation 分析技巧
通过以上方法可以对应用的整体内存使用情况有所了解,但内存不合理使用导致的内存警告往往是部分代码或视图导致的,我们往往要关注于某段时间或操作过程中内存的分配和使用情况,Allocation提供了这种功能。
比如在进入一个视图前或操作前,我们在Allocation面板左侧点击Mark Generation,这时候会产生Generation A节点,显示内存当前的情况:
比较测出内存泄露点
我们可以在进入视图后再点一次Mark Generation,在视图退出后再点一次Mark,这样三次产生的 Generation分别记录了进入前、进入后、关闭后,再最后一个Generation应该内存被合理释放,否则就代表了在这个视图或操作中有泄漏或不合理的地方。
以上只是Allocation的基本运用,设计出一套使用Allocation来合理测试的方案是比较复杂的,后续慢慢介绍。四:MLeaksFinderMLeaksFinder 提供了内存泄露检测更好的解决方案。只需要引入 MLeaksFinder,就可以自动在 App 运行过程检测到内存泄露的对象并立即提醒,无需打开额外的工具,也无需为了检测内存泄露而一个个场景去重复地操作。MLeaksFinder 目前能自动检测 UIViewController 和 UIView 对象的内存泄露,而且也可以扩展以检测其它类型的对象。
MLeaksFinder 的使用很简单,参照 https://github.com/Zepo/MLeaksFinder,基本上就是把 MLeaksFinder 目录下的文件添加到你的项目中,就可以在运行时(debug 模式下)帮助你检测项目里的内存泄露了,无需修改任何业务逻辑代码,而且只在 debug 下开启,完全不影响你的 release 包。
当发生内存泄露时,MLeaksFinder 会中断言,并准确的告诉你哪个对象泄露了。这里设计为中断言而不是打日志让程序继续跑,是因为很多人不会去看日志,断言则能强制开发者注意到并去修改,而不是犯拖延症。
中断言时,控制台会有如下提示,View-ViewController stack 从上往下看,该 stack 告诉你,MyTableViewController 的 UITableView 的 subview UITableViewWrapperView 的 subview MyTableViewCell 没被释放。而且,这里我们可以肯定的是 MyTableViewController,UITableView,UITableViewWrapperView 这三个已经成功释放了。
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Possibly Memory Leak.In case that MyTableViewCell should not be dealloced, override -willDealloc in MyTableViewCell by returning NO.View-ViewController stack: ( MyTableViewController, UITableView, UITableViewWrapperView, MyTableViewCell)'从 MLeaksFinder 的使用方法可以看出,MLeaksFinder 具备以下优点:
使用简单,不侵入业务逻辑代码,不用打开 Instrument
不需要额外的操作,你只需开发你的业务逻辑,在你运行调试时就能帮你检测
内存泄露发现及时,更改完代码后一运行即能发现(这点很重要,你马上就能意识到哪里写错了)
精准,能准确地告诉你哪个对象没被释放原理(http://wereadteam.github.io/2016/02/22/MLeaksFinder/?from=singlemessage&isappinstalled=0#u539F_u7406)
MLeaksFinder 一开始从 UIViewController 入手。我们知道,当一个 UIViewController 被 pop 或 dismiss 后,该 UIViewController 包括它的 view,view 的 subviews 等等将很快被释放(除非你把它设计成单例,或者持有它的强引用,但一般很少这样做)。于是,我们只需在一个 ViewController 被 pop 或 dismiss 一小段时间后,看看该 UIViewController,它的 view,view 的 subviews 等等是否还存在。
具体的方法是,为基类 NSObject 添加一个方法 -willDealloc
方法,该方法的作用是,先用一个弱指针指向 self,并在一小段时间(3秒)后,通过这个弱指针调用 -assertNotDealloc,而 -assertNotDealloc 主要作用是直接中断言。- (BOOL)willDealloc { __weak id weakSelf = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [weakSelf assertNotDealloc]; }); return YES;}- (void)assertNotDealloc { NSAssert(NO, @“”);}
这样,当我们认为某个对象应该要被释放了,在释放前调用这个方法,如果3秒后它被释放成功,weakSelf 就指向 nil,不会调用到 -assertNotDealloc
方法,也就不会中断言,如果它没被释放(泄露了),-assertNotDealloc
就会被调用中断言。这样,当一个 UIViewController 被 pop 或 dismiss 时(我们认为它应该要被释放了),我们遍历该 UIViewController 上的所有 view,依次调 -willDealloc,若3秒后没被释放,就会中断言。在这里,有几个问题需要解决:
不入侵开发代码
这里使用了 AOP 技术,hook 掉 UIViewController 和 UINavigationController 的 pop 跟 dismiss 方法,关于如何 hook,请参考 Method Swizzling。遍历相关对象
在实际项目中,我们发现有时候一个 UIViewController 被释放了,但它的 view 没被释放,或者一个 UIView 被释放了,但它的某个 subview 没被释放。这种内存泄露的情况很常见,因此,我们有必要遍历基于 UIViewController 的整棵 View-ViewController 树。我们通过 UIViewController 的 presentedViewController 和 view 属性,UIView 的 subviews 属性等递归遍历。对于某些 ViewController,如 UINavigationController,UISplitViewController 等,我们还需要遍历 viewControllers 属性。构建堆栈信息
需要构建 View-ViewController stack 信息以告诉开发者是哪个对象没被释放。在递归遍历 View-ViewController 树时,子节点的 stack 信息由父节点的 stack 信息加上子结点信息即可。例外机制
对于有些 ViewController,在被 pop 或 dismiss 后,不会被释放(比如单例),因此需要提供机制让开发者指定哪个对象不会被释放,这里可以通过重载上面的 -willDealloc
方法,直接 return NO 即可。特殊情况
对于某些特殊情况,释放的时机不大一样(比如系统手势返回时,在划到一半时 hold 住,虽然已被 pop,但这时还不会被释放,ViewController 要等到完全 disappear 后才释放),需要做特殊处理,具体的特殊处理视具体情况而定。系统View
某些系统的私有 View,不会被释放(可能是系统 bug 或者是系统出于某些原因故意这样做的,这里就不去深究了),因此需要建立白名单手动扩展
MLeaksFinder目前只检测 ViewController 跟 View 对象。为此,MLeaksFinder 提供了一个手动扩展的机制,你可以从 UIViewController 跟 UIView 出发,去检测其它类型的对象的内存泄露。如下所示,我们可以检测 UIViewController 底下的 View、Model:- (BOOL)willDealloc { if (![super willDealloc]) { return NO; } MLCheck(self.viewModel); return YES;}
这里的原理跟上面的是一样的,宏 MLCheck() 做的事就是为传进来的对象建立 View-ViewController stack 信息,并对传进来的对象调用 -willDealloc
方法。五:faceBook提供的内存泄露自动化测试:FBRetainCycleDetector、FBAllocationTracker、FBMemoryProfiler。让这工具真正闪光的是,在工程师内部构建的时候,它会连续的、自动的运行。
客户端部分自动化是简单的。我们在定时器上运行循环引用检测器,定期扫描内存去寻找循环引用,虽然这不是完全没有问题。当我们第一次运行分析器的时候,我们意识到它不足以很快的扫描整个内存空间。当它开始检测的时候,我们需要给它提供一组候选对象。
为了更有效的解决这个问题,我们开发了FBAllocationTracker。这个工具会主动跟踪NSObject
子类的创建和释放。它可以以一个很小的性能开销来获取任何类的任何实例。
对于客户端的自动化,只要在NSTimer
上使用FBRetainCycleDetector,再用FBAllocationTracker来抓取实例来配合跟踪就行。
现在,让我们来仔细看看后台会发生什么。
循环引用可以包含任何数量的对象。一个坏的连接会导致很多环的时候,这就复杂了。在环中,A→B是一个坏连接,创建了两个环:A-B-C-D 和 A-B-C-E。
这有两个问题:
我们不想给一个坏连接导致的两个循环引用分别标记。
我们不想给可能代表两个问题的两个循环引用一起标记,即使它们共享一个连接。所以我们需要给循环引用定义簇组(clusters),鉴于这些启发,我们写了个算法来找到这些问题。
在给定的时间收集所有的环。
对于每一个环,提取Facebook特定的类名。
对于每一个环,找到包含在环内的被报告的最小的环。
依据上面的最小环,将环添加到组中。
只报告最小环。最后一部分是找出谁第一时间偶然引入了循环引用。我们可以通过环中的”git/hg责任”的部分代码来猜测最近的变化所导致的问题。最后一个接触这个代码的人将会收到修复代码的任务。
整个系统如下:手动性能分析
虽然自动化有助于简化发现循环引用的过程,降低人员的消耗,手动性能分析依然有它的用武之地。我们创建的另一个工具允许任何人查看内存使用,甚至不需要把他的手机插到电脑上。
FBMemoryProfiler可以很容易的添加到任何应用程序,可以让你手动配置构建文件,可以让你在应用程序内运行循环应用检测。它会借用FBAllocationTracker和FBRetainCycleDetector来实现此功能。生成(Generations)
FBMemoryProfiler的一个很伟大的特性是“生成追踪(generation tracking)”,类似于苹果的Instruments的生成追踪。生成只是简单的在两次标记之间拍摄所有仍然活着的对象的快照。
使用FBMemoryProfiler的界面,我们可以标记生成,例如,分配三个对象。然后我们标记另一个生成,之后继续分配对象。第一个生成包含我们一开始的三个对象。如果任意一个对象被释放了,它会从我们第二个生成中移除。当我们有一个重复的任务,我们认为可能会内存泄露的时候,生成追踪是很有用的,例如,导航View Controller的进出。在每次开始我们的任务的时候,我们标记一个生成,然后,对之后的每个生成进行调查。如果一个对象不应该活这么长时间,我们可以在FBMemoryProfiler界面清楚地看到。
Check Out
无论你的应用程序是大是小,功能是多是少,好的工程师都应有好的内存管理。在这些工具的帮助之下,我们可以更简单的找到并修复这些内存泄露,所以我们可以花费更少的时间去手动处理,这样就可以有更多的时间去编写更好的代码。我们也希望你可以发现它们是有用的。在Github上check out下来吧。FBRetainCycleDetector, FBAllocationTracker 和 FBMemoryProfiler。

 

转载于:https://my.oschina.net/u/2562364/blog/906566

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/456424.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

玩Azkaban跳过的坑

文章目录一号坑&#xff1a;启动Azkaban报错&#xff1a;User xml file conf/azkaban-users.xml doesnt exist.二号坑&#xff1a;报错&#xff1a;failed SslSocketConnector0.0.0.0:8443: java.io.FileNotFoundException: /home/hadoop/app/azkaban/azkaban-web-2.5.0/bin/ke…

删除节点removeChild()

http://www.imooc.com/code/1700 删除节点removeChild() removeChild() 方法从子节点列表中删除某个节点。如删除成功&#xff0c;此方法可返回被删除的节点&#xff0c;如失败&#xff0c;则返回 NULL。 语法: nodeObject.removeChild(node) 参数: node &#xff1a;必需&…

机器学习自主解决安全威胁离我们还有多远?

曾经听见不止一次这样的问题&#xff1a; “机器学习会替代基于人工经验规则的安全解决方案么&#xff1f;”把这个问题放在去年来看&#xff0c;我们已经得到了非常多的讨论甚至是一些已经实际应用的解决方案&#xff0c;对于人工智能在安全以及其它各种对数据进行价值挖掘的场…

Vue:解决[Vue warn]: Failed to resolve directive: modle (found in Anonymous)

解决问题 [Vue warn]: Failed to resolve directive: modle (found in <ComponentA>) console.error(("[Vue warn]: " msg trace)); 原因是 我把model 写成了 modle 这类错误一般是单词写错了 (found in <Anonymous>) 解决思路

一行Python代码制作动态二维码

目录 1、普通二维码 2、艺术二维码 3、动态二维码 在GitHub上发现了一个比较有意思的项目&#xff0c;只需要一行Python代码就可以快捷方便生成普通二维码、艺术二维码(黑白/彩色)和动态GIF二维码。 GitHub网站参加&#xff1a;https://github.com/sylnsfar/qrcode 用法比…

Vue常用经典开源项目汇总参考-海量

Vue常用经典开源项目汇总参考-海量 Vue是什么&#xff1f; Vue.js&#xff08;读音 /vjuː/, 类似于 view&#xff09; 是一套构建用户界面的 渐进式框架。与其他重量级框架不同的是&#xff0c;Vue 采用自底向上增量开发的设计。Vue 的核心库只关注视图层&#xff0c;并且非常…

Pycharm常用高效技巧总结

文章目录1、PyCharm如何自动生成函数注释2、pycharm运行程序时在Python console窗口中运行3、Pycharm在创建py文件时,如何自动添加文件头注释4、Pycharm配置远程调试5、pycharm同一目录下无法import明明已经存在的.py文件1、PyCharm如何自动生成函数注释 一般在函数def()行下敲…

EntityFramework中常用的数据删除方式

最近在学EF&#xff0c;目前了解到删除操作有三种方式&#xff0c; 第一&#xff0c;官方推荐的先查询数据&#xff0c;再根据查询的对象&#xff0c;删除对象。 这是第一种&#xff0c;官方推荐 第二&#xff0c;自己创建一个对象&#xff0c;然后附加&#xff0c;然后删除。 …

Elasticsearch的前后台运行与停止(tar包方式)

备注&#xff1a;在生产环境中&#xff0c;往往一般用后台来运行。jps查看。 1、ES的前台运行 [hadoopdjt002 elasticsearch-2.4.3]$ pwd/usr/local/elasticsearch/elasticsearch-2.4.3[hadoopdjt002 elasticsearch-2.4.3]$ bin/elasticsearch 2、ES的后台运行 [hadoopdjt002 e…

解决pycharm运行Flask指定ip、端口更改无效

后来查了一下官网文档&#xff0c;原来Flask 1.0 版本不再支持之前的FLASK_ENV 环境变量了。 Prior to Flask 1.0 the FLASK_ENV environment variable was not supported and you needed to enable debug mode by exporting FLASK_DEBUG1. This can still be used to control…

Android中SimpleAdapter的使用—自定义列表

本人初学Android&#xff0c;今天研究到Adapter这块感觉挺有意思的&#xff0c;写了个自定义列表进行测试 首先我们新建一个layout列表布局文件&#xff0c;具体布局可以自己设定。 下面贴上我的自定义布局文件代码 1 <?xml version"1.0" encoding"utf-8&qu…

linux lvm扩容

linux lvm扩容 LVM磁盘管理 一、LVM简介... 1 二、 LVM基本术语... 2 三、 安装LVM... 3 四、 创建和管理LVM... 4 2、 创建PV.. 6 3、 创建VG.. 7 4、 创建LV.. 9 5、LV格式化及挂载... 10 一、LVM简介 LVM是 Logical Volume Manager(逻辑卷管理)的简写&#xff0c;它由Heinz …

Python基础常见面试题总结

文章目录基础知识题看程序写结果题编程题以下是总结的一些常见的Python基础面试题&#xff0c;帮助大家回顾基础知识&#xff0c;了解面试套路。会一直保持更新状态。PS&#xff1a;加粗为需要注意的点。基础知识题 1、深拷贝和浅拷贝的区别是什么&#xff1f; 深拷贝是将对象…

Flask-Script扩展命令行manager = Manager(app)

通过使用Flask-Script扩展&#xff0c;我们可以在Flask服务器启动的时候&#xff0c;通过命令行的方式传入参数。而不仅仅通过app.run()方法中传参&#xff0c;比如我们可以通过python hello.py runserver --host ip地址&#xff0c;告诉服务器在哪个网络接口监听来自客户端的连…

Python基础总结之常用内置方法总结

文章目录前言1、str1.1、内置方法&#xff1a;1.2、常用的内置方法1.3、String模块的一些方法2、list2.1、内置方法2.2、常用内置方法3、tupple3.1、内置方法3.2、常用内置方法4、dict4.1、内置方法4.2、常用内置方法5、其他5.1、几个sort的使用5.2、enumerate&#xff08;&…

线程的条件变量实例

情景1&#xff1a;Jack开着一辆出租车来到一个网站停车。看见没人就走了。过段时间。Susan来到网站准备乘车。可是没有来&#xff0c;于是就等着。过了一会Mike开着车来到了这个网站&#xff0c;Sunsan就上了Mike的车走了。如图所看到的&#xff1a;程序实现该情景&#xff1a;…

浅谈互联网寒冬与经济形势

文章目录前言&#xff1a;闲扯总结&#xff1a;前言&#xff1a; 作为刚进入职场一年多的小白来说&#xff0c;刚准备“猥琐发育涨经验”&#xff0c;却碰到这股互联网寒冬&#xff0c;也感到鸭梨山大。也许有人认为我在贩卖焦虑&#xff0c;但是现实真的很严峻。接下说下过去…

Java集合---LinkedList源码解析

一、源码解析1、 LinkedList类定义2、LinkedList数据结构原理3、私有属性4、构造方法5、元素添加add()及原理6、删除数据remove()7、数据获取get()8、数据复制clone()与toArray()9、遍历数据&#xff1a;Iterator()二、ListItr 一、源码解析 1、 LinkedList类定义。 public cla…

Mysql面试热身题集总结

文章目录前言1、热身题实践其他前言 一直有个想法&#xff1a;把面试需要的知识点全都总结一下&#xff0c;包括数据库&#xff0c;语言&#xff0c;算法&#xff0c;数据结构等知识&#xff0c;形成一个面试总结笔记&#xff0c;这样以后面试的时候只看这些文章回顾下就行了。…

Oracle执行计划解释

为什么80%的码农都做不了架构师&#xff1f;>>> 一&#xff0e;相关的概念 Rowid的概念&#xff1a;rowid是一个伪列&#xff0c;既然是伪列&#xff0c;那么这个列就不是用户定义&#xff0c;而是系统自己给加上的。 对每个表都有一个rowid的伪列&#xff0c;但是表…