美文网首页
26.内存安全

26.内存安全

作者: LucXion | 来源:发表于2021-07-28 09:39 被阅读0次

内存访问的三个性质:读还是写,访问的内存地址,访问的时长

只要包含以下情况中的任意两种,都会造成 访问冲突

  • 至少有一个是写访问
  • 它们访问的是同一个存储地址
  • 它们的访问在时间线上部分重叠
    • 重叠的访问主要出现在使用 in-out 参数的函数和方法或者结构体的 mutating 方法里

In-Out 参数的访问冲突

一个函数会对它所有的 in-out 参数进行长期写访问。in-out 参数的写访问会在所有非 in-out 参数处理完之后开始,直到函数执行完毕为止。如果有多个 in-out 参数,则写访问开始的顺序与参数的顺序一致。

因为操作符也是函数,它们也会对 in-out 参数进行长期访问。例如,假设 changeTwo(_:_:) 是一个名为 <^> 的操作符函数,那么 num1 <^> num1 也会造成像 changeTwo(&num1, &num1)一样的冲突。

var num1 = 1
var num2 = 2
func changeNum(with num:inout Int)->Int {
    return num + num1
}
print(changeNum(with:  &num1)) // 错误:changeNum 内部直接访问了 num1

func changeTwo(num1:inout Int,num2:inout Int)->Int{
    return num1 + num2
}
changeTwo(num1: &num1, num2: &num1) // 错误:包含写访问,访问同一个内存地址,访问时间线重叠

方法里 Self 的访问冲突

struct Player {
    var name: String
    var health: Int
    var energy: Int

    static let maxHealth = 10
    mutating func restoreHealth() {
        health = Player.maxHealth // 访问的不是实例属性,没问题
    }
}
extension Player {
    mutating func shareHealth(with teammate: inout Player) {
        balance(&teammate.health, &health)
    }
}
func balance(_ fromHealth:inout Int,_ toHealth:inout Int) {
    fromHealth = 1
    toHealth = 2
    print(fromHealth,toHealth)
}

var player = Player.init(name: "Li", health: 11, energy: 8)
//player.shareHealth(with: &player)// 错误:shareHealth内隐式访问self,会造成访问同一个内存地址
var player2 = Player.init(name: "Ming", health: 15, energy: 8)
player.shareHealth(with: &player2) // 正确 

属性的访问冲突

var player = Player.init(name: "Li", health: 11, energy: 8)
balance(&player.health, &player.energy) // 运行错误: 值类型,修改值的任何一部分都是对于整个值的修改,意味着其中一个属性的读或写访问都需要访问整一个值

func someFunction (){
    var player2 = Player.init(name: "Ming", health: 15, energy: 8)
    balance(&player2.health, &player2.energy) // 运行正常:改为本地变量而非全局变量,编译器就会可以保证这个重叠访问是安全的

限制结构体属性的重叠访问对于保证内存安全不是必要的。保证内存安全是必要的,但因为访问独占权的要求比内存安全还要更严格——意味着即使有些代码违反了访问独占权的原则,也是内存安全的,所以如果编译器可以保证这种非专属的访问是安全的,那 Swift 就会允许这种行为的代码运行。特别是当你遵循下面的原则时,它可以保证结构体属性的重叠访问是安全的:

  • 你访问的是实例的存储属性,而不是计算属性或类的属性
  • 结构体是本地变量的值,而非全局变量
  • 结构体要么没有被闭包捕获,要么只被非逃逸闭包捕获了

如果编译器无法保证访问的安全性,它就不会允许那次访问。

相关文章

  • 26.内存安全

    内存访问的三个性质:读还是写,访问的内存地址,访问的时长 只要包含以下情况中的任意两种,都会造成 访问冲突: 至少...

  • CLR简介(四)

    内存和类型安全 GC一个不怎么明显但是影响深远的功能就是内存安全。内存安全的意思很简单:只有程序只访问其分配(且没...

  • rust哲学--内存安全

    内存安全: 1-保证类型安全(侦测,优化,可读,抽象)保证程序行为意义明确,不出错。 2-安全内存管理模型,通过类...

  • 让程序员崩溃的瞬间(三)

    24. 调试 bug 25. 正在调试,突然内存溢出了 26. 需求文档又改了 27. 苦逼的后端工程师 28. ...

  • 启动优化之二进制重排

    一、虚拟内存和物理内存 进程如果能直接访问物理内存无疑是很不安全的,为了解决内存安全,现在的计算机和操作系统在物理...

  • 【RUST_BASIC】不安全 Rust

    1 简介 Rust 在编译时会强制执行的内存安全保证,但是 Rust 中还存不强制执行内存安全保证的不安全 Rus...

  • swift 内存安全

    Swift 会阻止你代码里不安全的行为。例如,Swift 会保证变量在使用之前就完成初始化,在内存被回收之后就无法...

  • Swift - 内存安全

    内存安全 默认情况下,Swift 会阻止你代码里不安全的行为。例如,Swift 会保证变量在使用之前就完成初始化,...

  • Leetcode PHP题解--D136 26. Remove

    D136 26. Remove Duplicates from Sorted Array 题目链接 26. Rem...

  • iOS 内存相关的基础知识

    为什么不能直接访问物理内存? 内存不够用。 内存数据不安全。 内存管理方案 相关知识点[https://jueji...

网友评论

      本文标题:26.内存安全

      本文链接:https://www.haomeiwen.com/subject/awiomltx.html