swift指针内存管理-指针类型使用

news2024/11/16 19:53:57

为什么说指针不安全

  • 我们在创建一个对象的时候,是需要在堆上开辟内存空间的
    但是这个内存空间的声明周期是有限的
    也就意味着如果使用指针指向这块内存空间,当这块内存空间的生命周期结束(引用计数为0),那么当前的指针就变成未定义的了

  • 创建的内存空间是有边界的,通过指针访问的内存空间超过已开辟内存空间的边界,也就是访问了一个未知的内存空间

  • 指针类型与内存的值类型不一致,也不安全,这一点参考 swift指针&内存管理-内存绑定

指针类型

Swift中的指针分为两类 typed pointer(指定指针数据类型) & raw pointer(原生指针-未指定指针数据类型)

在这里插入图片描述

如果需要开辟一段连续的内存空间,就可以使用 unsafeBufferPointer, 当然了unsafeMutableBufferPointer 就是可变的

连续的原生内存空间 unsafeRawBufferPointer / unsafeMutableRawBufferPointer , 这种指针需要结合 指针内存绑定来使用

原始指针-rawPointer 的使用

如何使用 rawPointer 来存储4个整型的数据

在存储之前,先了解几个概念

print("MemoryLayout<Int>.size = \(MemoryLayout<Int>.size)")
print("MemoryLayout<Int>.stride = \(MemoryLayout<Int>.stride)")
print("MemoryLayout<Int>.alignment = \(MemoryLayout<Int>.alignment)")
print("MemoryLayout<Int32>.size = \(MemoryLayout<Int32>.size)")
print("MemoryLayout<Int32>.stride = \(MemoryLayout<Int32>.stride)")
print("MemoryLayout<Int32>.alignment = \(MemoryLayout<Int32>.alignment)")
print("MemoryLayout<Int16>.size = \(MemoryLayout<Int16>.size)")
print("MemoryLayout<Int16>.stride = \(MemoryLayout<Int16>.stride)")
print("MemoryLayout<Int16>.alignment = \(MemoryLayout<Int16>.alignment)")

结果:

MemoryLayout.size = 8

MemoryLayout.stride = 8

MemoryLayout.alignment = 8

MemoryLayout.size = 4

MemoryLayout.stride = 4

MemoryLayout.alignment = 4

MemoryLayout.size = 2

MemoryLayout.stride = 2

MemoryLayout.alignment = 2

MemoryLayout 是用来测定内存的

stride是步长,也就是一段连续内存空间 指定类型指针的偏移最小单位

alignment是对齐字节,一段连续内存空间,指令读取内存数据,都是标准化操作,不会出现第一个整型读了8字节,下一个整型读了4字节这样

然后我们进行 4个整型的数据的存储

首先开辟一块内存空间

UnsafeMutableRawPointer.allocate(byteCount: Int, alignment: Int)

byteCount: 开辟内存空间的总的字节大小

alignment: 连续内存空间中 每一个整型数据的对齐大小

然后存储 - UnsafeMutableRawPointer - storeBytes(of: T, as: T.Type)

of - 存储的数据

as - 存储的数据的类型

let mP = UnsafeMutableRawPointer.allocate(
	byteCount: 4 * MemoryLayout<Int>.size, 
	alignment: MemoryLayout<Int>.stride)
	
for i in 0..<4 {
    mP.storeBytes(of: i, as: Int.self)
}
// 取出
for i in 0..<4 {
	let mV = mP.load(as: Int.self)
    let mV = mP.load(fromByteOffset: i * MemoryLayout<Int>.stride, as: Int.self)
    print("mV ===> \(mV)")
}

结果

mV ===> 3

mV ===> 3

mV ===> 3

mV ===> 3

为什么不是 0, 1, 2, 3

这是因为 mP 指向 UnsafeMutableRawPointer.allocate 开辟出来的一段连续内存空间首地址

mP.load(as: Int.self) 循环里每次取的都是 从首地址处取出 数据,所以总是一样的3

调整之后

let mP = UnsafeMutableRawPointer.allocate(
	byteCount: 4 * MemoryLayout<Int>.size, 
	alignment: MemoryLayout<Int>.stride)
	
for i in 0..<4 {
    mP.storeBytes(of: i, as: Int.self)
}
// 取出
for i in 0..<4 {
    let mV = mP.load(fromByteOffset: i * MemoryLayout<Int>.stride, as: Int.self)
    print("mV ===> \(mV)")
}

结果

mV ===> 3

mV ===> 0

mV ===> 16

mV ===> 0

这又是为何

因为 mP.storeBytes(of: i, as: Int.self) 每次也只是往 mP指向的连续内存空间的首地址里存储,所以最后存储的 3会覆盖前面的几次写值

let mP = UnsafeMutableRawPointer.allocate(
	byteCount: 4 * MemoryLayout<Int>.size, 
	alignment: MemoryLayout<Int>.stride)
	
for i in 0..<4 {
	// 正解
    mP.advanced(by: i * MemoryLayout<Int>.stride).storeBytes(of: i, as: Int.self)
}
// 取出
for i in 0..<4 {
    let mV = mP.load(fromByteOffset: i * MemoryLayout<Int>.stride, as: Int.self)
    print("mV ===> \(mV)")
}

结果

mV ===> 0

mV ===> 1

mV ===> 2

mV ===> 3

也可以直接 计算具体指针位置进行写值,前提是必须知道指针的类型才可以

for i in 0..<4 {
    (mP + i * MemoryLayout<Int>.stride).storeBytes(of: i, as: Int.self)
}

size/stride/alignment的理解

情况一

struct IFLObject1 {
    var age: Int
    var gender: Bool
}

print("MemoryLayout<IFLObject1>.size = \(MemoryLayout<IFLObject1>.size)")
print("MemoryLayout<IFLObject1>.stride = \(MemoryLayout<IFLObject1>.stride)")
print("MemoryLayout<IFLObject1>.alignment = \(MemoryLayout<IFLObject1>.alignment)")

结果

MemoryLayout.size = 9

MemoryLayout.stride = 16

MemoryLayout.alignment = 8

在这里插入图片描述
alignment 对齐是内存中布局的一种方式

小单位 按照大单位去补齐, 如果凑不齐,就空余一定的空间出来,看上去就跟集中箱一样,遵循标准化原则

age占8字节 + gender占1字节, size 大小就是9字节

size 9字节 不是 age大小8字节的倍数, 空闲一部分空间,凑齐8字节整数倍,stride步长就是16字节

stride 16字节 凑齐的方式就是按照 age8字节大小去对齐,所以 alignment 就是8字节对齐

情况二

class IFLobject2 {
    var age: Int = 0
    var gender: Bool = true
    var heigh: Double = 170
    var heigh1: Double = 170
    var heigh2: Double = 170
    var heigh3: Double = 170
}
print("MemoryLayout<IFLobject2>.size = \(MemoryLayout<IFLObject2>.size)")
print("MemoryLayout<IFLobject2>.stride = \(MemoryLayout<IFLObject2>.stride)")
print("MemoryLayout<IFLobject2>.alignment = \(MemoryLayout<IFLObject2>.alignment)")

结果

MemoryLayout.size = 8

MemoryLayout.stride = 8

MemoryLayout.alignment = 8

与结构体不同的是,struct属于值类型,栈上开辟空间,class 堆上开辟内存空间,指针大小为8字节, 所以8字节对齐,步长也是8字节

泛型指针的使用

泛型指针相比原生指针来说,就是当前指针绑定到了具体的类型

泛型指针访问过程中,并不是使用store load 方法进行存储 取值操作,而是使用到泛型指针内置的变量pointee

var age = 10
var age1 = withUnsafePointer(to: &age) {
    $0.pointee + 1
}
print("age1 = \(age1)")

结果

age1 = 11

另一种情况

var age = 10
withUnsafePointer(to: &age) {
    $0.pointee += 1
}

这种情况下 指针 $0 是不可变的,同时$0指向的内容 $0.pointee也是不可变的, 如果要操作,调整如下

var age = 10
withUnsafeMutablePointer(to: &age) {
    $0.pointee += 1
}
print("age = \(age)")

结果

age = 11

还有一种方式直接分配内存

var age = 10
let tPtr = UnsafeMutablePointer<Int>.allocate(capacity: 1)
tPtr.initialize(to: age)
print(tPtr.pointee)

结果

10

struct IFLObjStruct {
    var age: Int
    var height: Double
}
var tPtr = UnsafeMutablePointer<IFLObjStruct>.allocate(capacity: 5)
tPtr[0] = IFLObjStruct(age: 19, height: 170.0)
tPtr[1] = IFLObjStruct(age: 20, height: 171.0)
tPtr[2] = IFLObjStruct(age: 21, height: 172.0)
tPtr[3] = IFLObjStruct(age: 22, height: 173.0)
tPtr[4] = IFLObjStruct(age: 23, height: 174.0)

print(tPtr[4])

结果

IFLObjStruct(age: 23, height: 174.0)

还可以

struct IFLObjStruct {
    var age: Int
    var height: Double
}
var tPtr = UnsafeMutablePointer<IFLObjStruct>.allocate(capacity: 5)
tPtr[0] = IFLObjStruct(age: 19, height: 170.0)
tPtr[1] = IFLObjStruct(age: 20, height: 171.0)
tPtr[2] = IFLObjStruct(age: 21, height: 172.0)
tPtr[3] = IFLObjStruct(age: 22, height: 173.0)
tPtr[4] = IFLObjStruct(age: 23, height: 174.0)
tPtr.deinitialize(count: 5)
// 回收内存空间
tPtr.deallocate()

tPtr = UnsafeMutablePointer<IFLObjStruct>.allocate(capacity: 5)
for i in 0..<5 {
    tPtr.advanced(by: i).initialize(to: IFLObjStruct(age: 19 + i * 5, height: 170.0 + Double(i * 5)))
}
for i in 0..<5 {
    print(tPtr.advanced(by: i).pointee)
}

结果

IFLObjStruct(age: 19, height: 170.0)

IFLObjStruct(age: 24, height: 175.0)

IFLObjStruct(age: 29, height: 180.0)

IFLObjStruct(age: 34, height: 185.0)

IFLObjStruct(age: 39, height: 190.0)

注意:

tPtr.advanced by 参数 含义是 只需要标明移动多少个指针内存单位, 并不需要计算具体移动的内存块字节大小,

因为 泛型指针已经 指明了当前内存 绑定的具体类型, 与原生指针 adviced by 参数有所区别

一般情况下,我们会在 defer 中,也就是当前程序运行完成之后, 执行 deinitialize 与 deallocate

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

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

相关文章

mac m1 配置goland debbug

大概率无法使用goland的debug功能&#xff0c;如果自己安装没选对路径&#xff0c;也无法使用。原因是&#xff1a; go env 配置不对&#xff0c;需要指向 ARM64&#xff1b; dlv版本不对&#xff0c;需要使用 arm64 系列&#xff1b; dlv路径不对&#xff0c;需要使用 macarm…

Linux服务器使用git clone命令时报错的解决方案

在往GitHub上上传项目时&#xff0c;使用git clone xxxxx.git时候报错&#xff1a; “gnutls_handshake() failed: the TLS connection was non-properly terminated” 由系统的 git 默认使用的 libcurl4-gnutls-dev 造成&#xff0c;可以使用openssl解决. 但是这个过程也很多…

2022亚太B题赛题分享

高速列车的优化设计 2022年4月12日&#xff0c;中国高铁复兴CR450多机组成功实现单列列车速度435 km/h&#xff0c;相对速度870 km/h&#xff0c;创造了高铁多机组列车穿越明线和隧道速度的世界纪录。新一代标准动车组“复兴”是中国自主研发的具有全知识产权的新一代高速列车。…

Doris 5 处理Sentinel-1 生成干涉图 interferogram

Doris 5 处理Sentinel-1 Step 0 创建文件夹 首先创建一个文件夹用来准备数据处理&#xff0c;例如 “Doris_test1”&#xff0c;然后在该文件夹下创建五个文件夹&#xff0c;用来存放数据&#xff0c;例如 AOI (研究区的shp文件), archive_data (已下载的Sentinel-1 SLC文件&…

手部IK,自制动画,蒙太奇——开门手臂自动弯曲、靠墙手自动扶墙

开门手臂自动弯曲 实现效果&#xff1a;人物做出抬手的开门动画时&#xff0c;若手臂碰到静态网格物体&#xff0c;拳头不会穿过物体&#xff0c;而是会产生手臂IK弯曲动画效果。 重要参考资料&#xff1a; 学习UE4动画蓝图&#xff1a;配置手部IK_YakSue的博客-CSDN博客_ue…

ImageProvider工作流程和AssetImage 加载流程

Flutter 学习&#xff1a;ImageProvider工作流程和AssetImage 的自动分辨率适配原理https://cloud.tencent.com/developer/article/1748045上面流程为ImageProvider工作流程细节&#xff0c;作者已经写的很详细了&#xff0c;非常受用&#xff0c;现在接着上面作者内容讨论下As…

【32-业务开发-基础业务-规格参数-保存数据-查询数据-更新操作之数据回显展示-更新操作-前后端项目交互整合与测试-总结收获】

一.知识回顾 【0.三高商城系统的专题专栏都帮你整理好了&#xff0c;请点击这里&#xff01;】 【1-系统架构演进过程】 【2-微服务系统架构需求】 【3-高性能、高并发、高可用的三高商城系统项目介绍】 【4-Linux云服务器上安装Docker】 【5-Docker安装部署MySQL和Redis服务】…

1532_AURIX_TriCore内核架构_中断

全部学习汇总&#xff1a; GreyZhang/g_tricore_architecture: some learning note about tricore architecture. (github.com) 中断一直是我想了解关注的一个功能模块&#xff0c;因为感觉不同的芯片上这部分的设计差异比较大。而这部分也跟我们嵌入式软件的设计模式直接相关。…

使用HikariCP连接池常用配置讲解及注意事项

使用HikariCP连接池常用配置讲解及注意事项常遇到的几种错误Possibly consider using a shorter maxLifetime valueConnection is not available, request timed out after xxxxxmsNo operations allowed after connection closed常见配置及注释说明&#xff0c;可以使用并根据…

每日刷题2——指针概念

更新不易&#xff0c;麻烦多多点赞&#xff0c;欢迎你的提问&#xff0c;感谢你的转发&#xff0c; 最后的最后&#xff0c;关注我&#xff0c;关注我&#xff0c;关注我&#xff0c;你会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我…

Twins: Revisiting the Design of Spatial Attention in Vision Transformers

Twins: Revisiting the Design of Spatial Attention in Vision Transformers一、引言二、Twins-PCPVT三、Twins-SVT四、实验五、消融实验文章链接: https://arxiv.org/abs/2104.13840代码链接: https://github.com/Meituan-AutoML/Twins一、引言 在本文中&#xff0c;重新审…

基于Matlab计算经典CFAR阈值

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

基于开源 PolarDB-X 打造中正智能身份认证业务数据基座

一、公司及业务介绍 中正智能是全球领先的生物识别和身份认证公司之一。我们曾负责公安部指纹算法国家标准的起草、编写&#xff0c;具备从算法、终端、平台、设计、生产、交付全域自研的能力&#xff0c;拥有多项自主知识产权的产品&#xff0c;并积极与高校合作开展基础研发。…

【Rust 指南】并发编程|无畏并发的原因

文章目录前言1、线程1.1、通过 spawn 创建新线程1.2、join 方法2、move 强制所有权迁移3、使用消息传递跨线程传递数据3.1、Send 方法3.2 、Sync 方法前言 安全高效的处理并发是 Rust 诞生的目的之一&#xff0c;主要解决的是服务器高负载承受能力。 并发&#xff08;concurren…

石家庄正定县恢复种植 国稻种芯·中国水稻节:河北绘就画卷

石家庄正定县恢复种植 国稻种芯中国水稻节&#xff1a;河北绘就画卷 新华社记者 杨世尧 摄 河北日报 通讯员张 晓峰 摄影报道 新闻中国采编网 中国新闻采编网 谋定研究中国智库网 中国农民丰收节国际贸易促进会 国稻种芯中国水稻节 中国三农智库网-功能性农业农业大健康大会…

MongoDB备份与恢复

MongoDB备份与恢复 文章目录MongoDB备份与恢复1.备份恢复工具2.备份工具区别3.mongoexport导出工具命令4.导出MongoDB的表4.1.创建备份的目录4.2.登录数据库4.3.查询表和表中数据4.4.导出数据为json格式4.5.导出数据为csv格式5.mongoimport导入工具5.1.恢复json格式数据5.2.登录…

Python基础-3-列表

一&#xff1a;简述 列表是由一系列按特定顺序排列的元素组成&#xff0c;可以创建包含字母表中所有字母&#xff0c;数字或家庭成员姓名的列表&#xff1b;也可以将任何东西加入列表&#xff0c;其中的元素之间可以没有任何关系。列表中通常包含了多个元素&#xff0c;因此给…

HTTPS中间人攻击实验

HTTPS中间人攻击实验 一.实验基础 1、HTTPS概述 HTTPS (全称: Hyper Text Transfer Protocol over SecureSocketLayer)&#xff0c; 是以安全为目标的HTTP通道&#xff0c;在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。 默认端口&#xff1a;443 SSLspli…

【无人机】基于拓展卡尔曼滤波时序四旋翼无人机状态跟踪附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

SpringBoot+Vue项目实现疫情期间社区出入管理系统

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue.js 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JD…