当前位置: 首页 > news >正文

《Effective Objective-C》阅读笔记(下)

目录

内存管理

理解引用计数

引用计数工作原理

自动释放池

保留环

以ARC简化引用计数

使用ARC时必须遵循的方法命名规则

变量的内存管理语义

ARC如何清理实例变量

在dealloc方法中只释放引用并解除监听

编写“异常安全代码”时留意内存管理问题

以弱引用避免保留环

以“自动释放池块”降低内存峰值

用“僵尸对象”调试内存管理问题

不要使用retainCount

块与大中枢派发

理解“块”这一概念

块的基础知识

块的内部结构

全局块、栈块及堆块

为常用的块类型创建typedef

用handler块降低代码分散程度

用块引用其所属对象时不要出现保留环

多用派发队列,少用同步锁

​编辑

多用GCD,少用performSelector系列方法

掌握GCD及操作队列的使用时机

通过Dispatch Group机制,根据系统资源状况来执行任务

使用dispatch_once来执行只需运行一次的线程安全代码

不要使用dispatch_get_current_queue

系统框架

熟悉系统框架

多用枚举块,少用for循环

对自定义其内存管理语义的collection使用无缝桥接

构建缓存时选用NSCache而非NSdictionary

精简initiakize与load的实现代码

别忘了NSTimer会保留其目标对象


内存管理

理解引用计数

OC使用引用计数来管理内存。

引用计数工作原理

NSObject协议声明了下面三个方法来操作计数器,以递增或递减其值:

retain 递增保留计数

release 递减保留计数

autorelease 待清理“自动释放池”,再递减保留计数

对象被创建后保留计数的变化过程如下图所示:

一般调用完release后都会清空指针,这就能保证不会出现可能指向无效对象的指针。

自动释放池

有时可以不调用release,改为调用autorelease,此方法会在稍后递减计数,通常是下一次“事件循环”时递减。

使用自动释放池autorelease可以延长对象生命期,使其在跨越方法调用边界后依然可以存活一段时间。

保留环

引用计数经常要注意的一个问题是“保留环”,“保留环”会导致内存泄漏,因为循环中的对象保留计数不会降为0,通常采用“若引用”来解决这一问题。

以ARC简化引用计数

ARC,即自动引用计数,所做的事情就是自动管理引用计数。由于ARC自动执行retain、release、autorelease等操作,所以不能调用上述方法

ARC在调用这些方法时,并不通过消息派发机制,而是直接调用其底层C语言版本,这样性能更好。

使用ARC时必须遵循的方法命名规则

若方法名以下列词语开头,则其返回的对象归调用者所有

若方法名不以上述四个词语开头,则表示其所返回的对象不归调用者所有。

变量的内存管理语义

在应用程序中,可用下列修饰符来改变局部变量与实例变量的语义:

通过__weak局部变量可以打破由块所引入的“保留环”。

ARC如何清理实例变量

ARC会借助OC特性来生成清理例程,来自动清理OC对象,所以ARC环境下通常无需再编写dealloc方法

不过如果有非OC的对象,那么仍然需要清理,dealloc方法可以这样写:

在dealloc方法中只释放引用并解除监听

对象在经历其生命期后,最终会为系统所回收,这时就要执行dealloc方法了。dealloc方法中要做的主要就是释放对象所拥有的引用。如果对象拥有其他非OC对象,那就要手工释放。

dealloc方法中还要把配置的观测行为清理掉,比如用NSNotificationCenter订阅的通知,dealloc可以这样写:

有一些开销较大或系统内稀缺的资源不在dealloc中释放,比如文件描述符、套接字、大块内存等。通常的做法是:实现另一个方法,当对象使用完后,就调用此方法。

这种对象所属的类,接口可以这样写:

#import <Foudation/Foudation.h>
@interface EOCServerConnection : NSObject
- (void)open:(NSString*)address;
- (void)close;
@end

该类与开发者的约定是:想打开连接,就调用“open:”方法,连接完毕就调用close方法。

close与dealloc方法可以这样写:

#import <Foudation/Foudation.h>
@interface EOCServerConnection : NSObject
- (void)open:(NSString*)address;
- (void)close;
@end

还要注意:dealloc中不要随便调用其他方法,执行异步任务的方法不应在dealloc里调用,只能在正常状态下执行的方法不应在dealloc里调用,属性的存取方法不应在dealloc里调用。

编写“异常安全代码”时留意内存管理问题

在try块中,如果先保留了某个对象,在释放它以前又抛出了异常,那么除非catch块能处理此问题,否则对象所占内存就将泄漏。

在手动管理引用计数时,要使用@finally块,并在块中释放对象,这样无论是否抛出异常,其中的代码都保证会运行且只运行一次。

当自动管理引用计数时,需要打开-fobjc-arc-exceptions标志,该标志默认关闭,只有在打开时,才会自动管理异常的引用计数,不过降低运行效率。

当遇到大量异常捕获操作时,就要考虑重构代码,用NSError式错误信息传递法来取代异常。

以弱引用避免保留环

最简单的保留环就是两个对象互相引用对方。

保留环会导致内存泄漏

如果只剩一个引用还指向保留环中的实例,而现在又把这个引用移除,那么整个保留环就泄漏了。

避免保留环最佳方式是弱引用,这种引用经常用来表示“非拥有关系”,将属性声明为unsafe_unretained或weak即可。

两者都会对属性弱引用,区别只是对象回收后的行为:

以“自动释放池块”降低内存峰值

嵌套自动释放池,可以控制应用的内存峰值,使其不致过高。

比如这段代码:

如果方法创建临时对象,那这些对象即便不再使用,也依然存活,直到系统将其释放并回收,意味着所有临时对象都要等for循环执行完才会释放。这会导致程序所占内存量持续上涨。

当循环长度取决于用户输入时更如此,比如:

这时,增加一个自动释放池,把循环内的代码包裹在“自动释放池块”中,那么循环中自动释放的对象就会放在这个池,内存峰值就会降低

用“僵尸对象”调试内存管理问题

Cocoa提供了“僵尸对象”这一功能,当功能启用后,系统会把所有已经回收的实例转化为“僵尸对象”,而不会真正回收它们。这种对象内存不可能遭到覆写,并且收到消息后会抛出异常,准确说明发送过来的消息,并描述回收之前的那个对象。僵尸对象是调试内存管理问题的最佳方式。

将NSZombieEnabled环境变量设为YES,即可开启此功能。开启功能后,系统会修改对象的isa指针,指向特殊的僵尸类,从而使对象变为僵尸对象,他会相应所有选择子,响应方式为:打印一条包含信息内容及其接收者的消息,然后终止应用程序

不要使用retainCount

ARC中已经废弃了retainCount这一方法,而在不启用ARC时,也不应该使用这一方法。

这个方法之所以无用,原因在于:它所返回的保留计数只是某个给定时间点上的值。

块与大中枢派发

理解“块”这一概念

块可以实现闭包

块的基础知识

块与函数类似,只不过是直接定义在另一个函数里的,和定义它的函数共享同一个范围内的东西,用符号“^”来表示,后面跟一对花括号。

块类型的语法结构如下:

块的强大之处是:在声明它的范围内,所有变量都可以为其所捕获,但是默认情况下,不可以在块里修改。

如果声明时加上__block修饰符,这样就可以在块内修改了。

如果块捕获了对象类型,就会自动保留它,就会导致一个问题,块本身也具有引用计数,这样就很容易导致循环引用。

块的内部结构

栈的内存布局如图:

这里invoke变量是个函数指针,指向块的实现代码,descriptor是指向结构体的指针,结构体中声明了块对象的总体大小,还声明了copy与dispose两个辅助函数对应的函数指针。

全局块、栈块及堆块

定义块时,所占内存区域是分配在栈中的,离开相应范围后,栈内存可能被覆写。

将块对象发送copy消息就可以拷贝,把块从栈复制到堆。此后再调用copy,只会递增块对象引用计数

除了栈块和堆块,还有全局块,这种块不会捕捉任何状态,也不需要,块所使用的内存区域在编译器就已经确定了。这种块可以声明在全局内存中,不需要在栈中创建。

全局块的拷贝是个空操作,它实际上相当于单例。

为常用的块类型创建typedef

块类型的语法结构如下:

为了简化,可以使用typedef为块起一个已读的别名,比如这样:

现在可以直接使用新类型了。

当块作为参数时,也可以简化,比如:

简化后:

使用类型定义还有个好处,就是在打算重构块时,会很方便,只要修改类型定义处即可

用handler块降低代码分散程度

为用户界面编码时,经常异步执行任务,如果使用委托模式,那么处理数据的代码总是在受委托者处实现,如下图:

而如果改用块来写的话,代码就会变得更加清晰。

如此一来,代码就变得好懂许多了。

除此之外,委托模式还有一个缺点:如果类要分别使用多个获取器下载不同数据,那就得在delegate回调方法里根据传入参数来切换。

如果使用块,就可以将实现代码与委托者内联在一起。

在设计API时,如果用到了handler块,那就可以增加一个参数,使调用者可以通过此参数来决定应该把块安排在哪个队列上执行

用块引用其所属对象时不要出现保留环

使用块很容易导致“保留环”

有两种常见情况。第一种如下例:

当使用block捕获self时,就可能造成这种情况,这时应该等闭包执行完后,再打破保留环

另一种情况是互相引用,这时常见的方法是不保留引用,设定一套机制,令获取器对象自己设法保持存活。

多用派发队列,少用同步锁

在GCD出现之前,有两种办法来实现同步机制,第一种是“同步块”(@synchronized),第二种是直接使用NSLock对象。这两种方法都有其缺陷,替代方案就是GCD。

有种简单而高效的办法可以代替同步块或锁对象,那就是使用“串行同步队列”。GCD在底层实现。可以做许多优化。

比如属性的存取:

将属性的访问操作都放在串行队列中,就可以实现同步。

如果把设置方法改为异步派发,就可以进一步优化

然而,获取方法与设置方法不能并发执行,但多个获取方法可以并发执行。将并发队列与栅栏块结合,可以进一步优化。

在队列中,栅栏块必须单独执行,不能与其他块并行。

实现代码也很简单:

_syncQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
- (NSString*)someString {__block NSString *localSomeString;dispatch_sync(_syncQueue, ^{localSomeString = _someString;});return localSomeString;
}
​
- (void)setSomeString:(NSString*)someString{dispatch_barrier_async(_syncQueue, ^{_someString = someString;});
}

多用GCD,少用performSelector系列方法

使用performSelector方法,可以动态绑定消息,如下图:

但是这种方法不仅可能导致内存泄漏,还很难传达一些非对象类型参数。

避免这些限制和缺陷,方法就是使用块,而perform方法提供的那些线程功能,都可以通过在大中枢派发机制中使用块来执行,延后执行可以用dispatch_after来实现,在另一个线城上执行任务可以通过dispatch_sync及dispatch_async来实现

掌握GCD及操作队列的使用时机

有时使用NSOperationQueue要比使用GCD技术要更合适。

用NSOperationQueue类的“addOperationWithBlock:”方法搭配NSBlockOperation类使用操作队列,语法与GCD非常类似,但使用下来有以下好处:

通过Dispatch Group机制,根据系统资源状况来执行任务

Dispatch group是GCD的一项特性,能够把任务分组。

与dispatch group相关的有以下几个函数:

dispatch_group_tdispatch_group_create// 创建分组
void dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_bloack_t block);//管理分组
void dispatch_group_enter(dispatch_group_t group);
void dispatch_group_leave(dispatch_group_t group);//管理分组

有两个方法可以用于等待dispatch group执行完毕:

long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);
void dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

二者的区别是:前者会阻塞当前线程,而后者只会在完成任务后进行通知。

未必一定要使用dispatch group,使用异步派发加单个队列也可以实现该效果。然而,使用dispatch group,GCD会根据系统资源状况来调度这些任务。若不采用group,则不仅性能有所下降,还需要额外代码来防止死锁

使用dispatch_once来执行只需运行一次的线程安全代码

在GCD中,有一种很好的方式实现单例,采用以下函数:

void dispatch_once(dispatch_once_t *token, dispatch_block_t block);

此函数接受一个参数,只要这个参数相同,那么这个块里的代码便只执行一次。

可以这样实现单例:

这个参数应该声明在static或global作用域中。

不要使用dispatch_get_current_queue

dispatch_get_current_queue这个函数已经被弃用了。使用这个函数时,容易造成死锁。并且这个函数的行为也总是与预计不符。因为队列存在一套层级体系。

所以使用该函数检查当前队列是否为执行同步派发所用的队列,并不总是奏效。这个函数所返回的不一定是API指定的那个,有可能是API内部的那个同步队列。

为了解决这个问题,最好的办法是通过GCD提供的功能来设定“队列特有数据”,通过队列特有数据来解决不可重入导致的死锁。

系统框架

熟悉系统框架

许多系统框架可以直接使用,最重要的是Foundation与CoreFoundation。

许多常见任务都能用框架来做,例如音频与视频处理、网络通信、数据管理等。

多用枚举块,少用for循环

遍历collection有四种方式,最基本的是for循环,其次是NSEnumerator类和for...in...快速便利法,最新、最先进的是“块枚举法”。

以数组为例,NSArray中定义了这个方法

- (void)enumerateObjectsUsingBlock:(void(^)id object, NSUInteger idx, BOOL *stop)block

通过这种方法遍历collection,可以直接从块里获取更多信息。遍历数组时可以知道当前下标,遍历字典可以同时获取键值,还可以修改块的方法签名以免进行类型转换操作

对自定义其内存管理语义的collection使用无缝桥接

使用无缝桥接技术,可以在Foudation框架中的OC对象与CoreFoudation框架中的C语言数据结构之间来回转换。

使用无缝桥接,可以将collection转换为具备特殊内存管理语义的collection。

比如字典的键为“拷贝”,而值为“保留”,这时就只能使用无缝桥接来改变语义。

CF框架中的可变字典叫CFMutableDictionary,可通过下列方法来制定键和值的内存管理语义:

构建缓存时选用NSCache而非NSdictionary

构建缓存时,应选用NSCache而非NSdictionary。

NSCache的优势在于:当系统资源快要耗尽时,它可以自动删减缓存

NSCache对象可以设置上限来限制缓存中的对象总个数和成本。

NSCache经常与NSData和NSPurgeableData搭配使用。将NSPurgeableData与NSCache搭配使用,可以实现自动清除数据的功能。

精简initiakize与load的实现代码

类的初始化有两个方法,分别是load和initialize

load方法的问题在于,执行时系统处于“脆弱状态”,在执行时必然执行超类的load方法,如果依赖程序库,那库里所有相关类的load方法必定会先执行,但是根据某个库,无法判定各个类的载入顺序。因此,在load方法里使用其他类是不安全的。

load方法务必实现精简一些,因为整个程序在执行load时都会阻塞。

initialize方法会在程序首次调用该类之前调用且只调用一次。它与load不同之处在于:

1.initiakize为惰性调用

2.执行initialize时,系统处于正常状态,也能确保一定是“线程安全的环境”中执行。

3.如果某个类为实现initialize,就会运行超类的实现代码。

initialize方法在实现时也尽量精简。

别忘了NSTimer会保留其目标对象

使用重复执行模式的计时器,很容易引入“保留环”

如果创建本类的实例,并调用startPolling方法,创建计时器时,由于目标对象是self,所以要保留此实例。然而,实例也保留了计时器。因此就产生了保留环。

这时可以拓展NSTimer的功能,用“块”来打破保留环。不过需要创建分类,将实现代码加入分类中。

- (void)startPolling{__weak EOCClass *weakSelf = self;_pollTimer = [NSTimer eoc_scheduledTimerWithTimeInterval:5.0 block: ^{EOCClass *strongSelf = weakSelf;[strongSelf p_doPoll];} repeats:YES];
}

这段代码先定义了一个弱引用,令其指向self,然后捕获这个引用,而不是原本的self变量,这样self就不会被计时器所保留块开始执行时,立即生成strong引用,以保证实例在执行期间持续存活。

相关文章:

《Effective Objective-C》阅读笔记(下)

目录 内存管理 理解引用计数 引用计数工作原理 自动释放池 保留环 以ARC简化引用计数 使用ARC时必须遵循的方法命名规则 变量的内存管理语义 ARC如何清理实例变量 在dealloc方法中只释放引用并解除监听 编写“异常安全代码”时留意内存管理问题 以弱引用避免保留环 …...

解释Promise的工作原理及其状态

Promise的工作原理及其状态 1. 什么是Promise&#xff1f; Promise是JavaScript中的一种用于处理异步操作的对象。它代表一个可能在未来某个时间点完成的操作&#xff0c;并且可以有三种状态&#xff1a;待定&#xff08;pending&#xff09;、已解决&#xff08;fulfilled&a…...

SHELL32!ILCombine函数分析之连接两个idl

SHELL32!ILCombine函数分析之连接两个idl 第一部分&#xff1a; STDAPI_(LPITEMIDLIST) ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { // Let me pass in NULL pointers if (!pidl1) { if (!pidl2) { return NULL; …...

es 生产集群的部署架构是什么?每个索引的数据量大概有多少?每个索引大概有多少个分片?

Elasticsearch 生产集群部署架构及面试解析 在后端面试中&#xff0c;Elasticsearch&#xff08;ES&#xff09;是一个经常被问到的技术点&#xff0c;尤其是涉及到 生产环境的部署架构。面试官往往希望通过这个问题来验证你是否有真正的生产经验&#xff0c;而不仅仅是玩过一…...

Qt跨线程信号槽调用:为什么信号不能像普通函数那样调用

1. 信号与槽机制的基本原理 在 Qt 中&#xff0c;信号与槽机制是一种事件驱动的通信方式&#xff0c;用于对象之间的解耦交互。其关键特点如下&#xff1a; 信号不能直接调用 信号只是一个声明&#xff0c;并没有实际的函数实现。它们通过 emit 关键字在对象内部被触发&…...

ollama和open-webui部署ds

博客地址&#xff1a; ollama和open-webui部署ds 引言 最近&#xff0c;deepseek是越来越火&#xff0c;我也趁着这个机会做了下私有化部署&#xff0c;我这边使用的ollama和 open-webui实现的web版本 ollama 简介 Ollama 是一个开源的工具&#xff0c;专门用于简化机器学…...

泛微Ecode新增Button调用服务器中的JSP页面里的方法

前言 前端Ecode调用 后端接口编写 JSP文件方法 总结 前言 因为我们是从之前E8版本升级到E9的&#xff0c;所以会有一些接口是通过jsp文件来实现前后端调用的&#xff0c;这里介绍的就是如果你有接口是写在jsp文件里面调用的&#xff0c;但是你又想在Ecode中调用的对应的接…...

LVS+Keepalived高可用群集配置案例

以下是一个 LVSKeepalived 高可用群集配置案例&#xff1a; 1、环境准备 LVS 主调度器&#xff08;lvs1&#xff09;&#xff1a;IP 地址为 192.168.8.101&#xff0c;心跳 IP 为 192.168.4.101LVS 备调度器&#xff08;lvs2&#xff09;&#xff1a;IP 地址为 192.168.8.102…...

杰发科技AC7801——滴答定时器获取时间戳

1. 滴答定时器 杰发科技7801内部有一个滴答定时器&#xff0c;该定时器是M0核自带的&#xff0c;因此可以直接用该定时器来获取时间戳。 同样&#xff0c;7803也可以使用该方式获取时间戳。 2. 滴答定时器原理 SysTick是一个24位的递减计数器&#xff0c;它从预设的重装载值…...

Pycharm使用matplotlib出现的问题(1、不能弹出图表 2、图表标题中文不显示)

Pycharm使用matplotlib出现的问题 问题1&#xff1a;Pycharm调试时出现&#xff1a;AttributeError: module backend_interagg has no attribute FigureCanvas. Did you mean: FigureCanvasAgg? 排查原因&#xff1a;可能是由于matplotlib后端设置不正确或与运行环境不兼容引…...

Cursor+pycharm接入Codeuim(免费版),Tab自动补全功能平替

如题&#xff0c;笔者在Cursor中使用pycharm写python程序&#xff0c;试用期到了Tab自动补全功能就不能用了&#xff0c;安装Codeuim插件可以代替这个功能。步骤如下&#xff1a; 1. 在应用商店中搜索扩展Codeuim&#xff0c;下载安装 2. 安装完成后左下角会弹出提示框&#x…...

spring--ApplicationContext和BeanFactory的区别(源码)

ApplicationContext 和 BeanFactory 是 Spring 框架中两个核心的接口&#xff0c;它们都用于管理和访问 Spring 容器中的 Bean&#xff0c;但在功能和使用场景上有显著的区别。以下是它们的详细对比&#xff0c;并结合源码进行讲解。 一、 功能对比 特性BeanFactoryApplicati…...

HTMLS基本结构及标签

HTML5是目前制作网页的核心技术&#xff0c;有叫超文本标记语言。 基本结构 声明部分位于文档的最前面&#xff0c;用于向浏览器说明当前文档使用HTML标准规范。 根部标签位于声明部分后&#xff0c;用于告知浏览器这是一个HTML文档。< html>表示文档开始&#xff0c;&l…...

【蓝桥杯嵌入式】各模块学习总结

系列文章目录 留空 文章目录 系列文章目录前言一、LED模块1.1 赛题要求1.2 模块原理图1.3 编写代码1.4 赛题实战 二、LCD模块2.1 赛题要求2.2 模块原理图2.3 编写代码2.4 赛题实战 三、按键模块3.1 赛题要求3.2 模块原理图3.3 编写代码3.4 赛题实战 四、串口模块4.1 赛题要求4…...

Vue的项目创建以及项目目录与组合式API

一.创建Vue 1.Vue-CLI:创建Vue的脚手架工具 2.Create-vue&#xff1a;是Vue官方提供的脚手架之一,底层采用官方自主研发的vite,快捷&#xff0c;开发方便。 3.准备工作:系统中需要安装nodejs环境&#xff0c;在该环境中提供npm包管理器 4.创建Vue项目的命令:npm init vuela…...

数据结构秘籍(二)图(含图的概念、存储以及图的两大搜索)

1 引言 线性数据结构的元素满足唯一的线性关系&#xff0c;每个元素&#xff08;初第一个和最后一个外&#xff09;只有一个直接前趋和一个直接后继。树形数据结构的元素之间有着明显的层次关系。但是图形结构的元素之间的关系是任意的。 什么是图&#xff1f; 简单来说&…...

前端八股——JS+ES6

前端八股&#xff1a;JSES6 说明&#xff1a;个人总结&#xff0c;用于个人复习回顾&#xff0c;将持续改正创作&#xff0c;已在语雀公开&#xff0c;欢迎评论改正。...

Python 课堂点名桌面小程序

一、场景分析 闲来无事&#xff0c;老婆说叫我开发一个课堂点名桌面小程序&#xff0c;给她在课堂随机点名学生问问题。 人生苦短&#xff0c;那就用 Python 给她写一个吧。 二、依赖安装 因为要用到 excel&#xff0c;所以安装两个依赖&#xff1a; pip install openpyxl…...

【Java基础】Java中new一个对象时,JVM到底做了什么?

Java中new一个对象时&#xff0c;JVM到底做了什么&#xff1f; 在Java编程中&#xff0c;new关键字是我们创建对象的最常用方式。但你是否想过&#xff0c;当你写下new MyClass()时&#xff0c;Java虚拟机&#xff08;JVM&#xff09;到底在背后做了哪些工作&#xff1f;今天&…...

C#中的字典怎么使用?

在C#中&#xff0c;Dictionary<TKey, TValue> 是一个泛型集合类&#xff0c;用于存储键值对&#xff08;key-value pairs&#xff09;。它提供了快速的查找、插入和删除操作&#xff0c;适合需要根据键快速查找值的场景。以下是 Dictionary 的基本用法和常见操作&#xf…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...