美文网首页
十八、内存访问冲突、指针

十八、内存访问冲突、指针

作者: 爱玩游戏的iOS菜鸟 | 来源:发表于2020-02-12 20:39 被阅读0次

内存访问冲突(Conflicting Access to Memory)

产生内存访问冲突的条件

内存访问冲突会在两个访问满足下列条件时发生:(3个条件同时满足)

  1. 至少一个是写入操作
  2. 它们访问的是同一块内存
  3. 它们的访问时间重叠(比如同一个函数内)
//不存在内存访问冲突
func plus(_ num: inout Int) -> Int{
    num += 1
    return num
}
var num = 1
print(plus(&num))

//存在内存访问冲突
var step = 1
func increment(_ num :inout Int){
    num += step//同时访问和修改 访问冲突
    //Simultaneous accesses to 0x100006668, but modification requires exclusive access.
}

increment(&step)

//存在内存访问冲突
func balance(_ x:inout Int, _ y:inout Int){
    let sum = x + y
    x = sum / 2
    y = sum - x
}

var num1 = 42
var num2 = 30
balance(&num1, &num2)//OK
balance(&num1, &num1)//Error

//存在内存访问冲突
struct Player {
    var name: String
    var health: Int
    var energy: Int
    mutating func shareHealth(with teammate: inout Player){
        balance(&teammate.health, &health)
    }
}
var Oscar = Player(name: "Oscar", health: 10, energy: 10)
var maria = Player(name: "maria", health: 5, energy: 5)
Oscar.shareHealth(with: &maria)//OK
Oscar.shareHealth(with: &Oscar)//Error

//结构体访问冲突
var tulpe = (health: 10, energy: 20)
balance(&tulpe.health, &tulpe.energy)//Error

var holly = Player(name: "holly", health: 10, energy: 20)
balance(&holly.health, &holly.energy)//Error
不会内存访问冲突的情况

如果下面的条件可以满足,就说明重叠访问结构体的属性是安全的

  • 只访问实例存储属性,不是计算属性或者类属性
  • 结构体是局部变量而非全局变量
  • 结构体要么没有被闭包捕获要么只被非逃逸闭包捕获
func test(){
    var tulpe = (health: 10, energy: 20)
    balance(&tulpe.health, &tulpe.energy)//Error
    
    var holly = Player(name: "holly", health: 10, energy: 20)
    balance(&holly.health, &holly.energy)
}

指针

Swift也有专门的指针类型,这些都被定性为"Unsafe",常见的有一下4种类型:

  • UnsafePointer<Pointee>类似于const Pointee *
  • UnsafeMutablePointer<Pointee>类似于Pointee *
  • UnsafeRawPointer类似于const void *
  • UnsafeMutableRawPointer类似于void *
var age = 10
func test1(_ ptr:UnsafeMutablePointer<Int>){
    ptr.pointee += 10
}

func test2(_ ptr:UnsafePointer<Int>){
    print(ptr.pointee)
}

test1(&age)
test2(&age)//20
print(age)//20

var age2 = 20
func test3(_ ptr:UnsafeMutableRawPointer){
    ptr.storeBytes(of: 20, as: Int.self)
}

func test4(_ ptr:UnsafeRawPointer){
    print(ptr.load(as: Int.self))
}

test3(&age2)
test4(&age2)//20
print(age)//20
指针的应用示例
var arr = NSArray(objects: 11,22,33,44)

arr.enumerateObjects { (obj, idx, stop) in
    print(idx,obj)
    if idx == 2 {//下标为2就停止遍历
        stop.pointee = true
    }
}

for (idx,obj) in arr.enumerated(){
    print(idx , obj)
    if idx == 2 {
        break
    }
}
  1. 获得指向某个变量的指针
var age = 11

var prt1 = withUnsafeMutablePointer(to: &age) { $0 }

var prt2 = withUnsafePointer(to: &age) { $0 }

prt1.pointee = 22
print(prt2.pointee)//22
print(age)//22

var ptr3 = withUnsafeMutablePointer(to: &age) { UnsafeMutableRawPointer($0) }

var ptr4 = withUnsafePointer(to: &age) { UnsafeRawPointer($0) }
ptr3.storeBytes(of: 33, as: Int.self)
print(ptr4.load(as: Int.self))
print(age)
  1. 获得指向堆空间实例的指针
class Person { }
var person = Person()
var ptr = withUnsafePointer(to: &person) { UnsafeRawPointer($0) }
var heapPtr = UnsafeRawPointer(bitPattern: ptr.load(as: UInt.self))
print(heapPtr!)
  1. 创建指针
var ptr = UnsafeRawPointer(bitPattern: 0x100001234)
//创建
var ptr1 = malloc(16)//分配16个字节的堆空间 
//存
ptr1?.storeBytes(of: 11, as: Int.self)//11只占8个字节 所以只初始化前8个字节
ptr1?.storeBytes(of: 22, toByteOffset: 8, as: Int.self)//初始化 后8个字节
//取
print((ptr1?.load(as: Int.self))!)//11 取前8个字节
print((ptr1?.load(fromByteOffset: 8, as: Int.self))!)//22 取后8个字节
//销毁
free(ptr1)

var ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
ptr.storeBytes(of: 11, as: Int.self)// 初始化前8个字节 
ptr.advanced(by: 8).storeBytes(of: 22, as: Int.self)//初始化 后8个字节

print(ptr.load(as: Int.self))//11 取前8个字节
print(ptr.advanced(by: 8).load(as: Int.self))//22 取后8个字节
ptr.deallocate()//销毁
//Int类型已确定
var ptr = UnsafeMutablePointer<Int>.allocate(capacity: 3)//3 * 8 24个字节
ptr.initialize(to: 11)
ptr.successor().initialize(to: 22)//后进指向的内存地址赋值 下一个Int空间
ptr.successor().successor().initialize(to: 33)

print(ptr.pointee)//11
print((ptr + 1).pointee)//22
print((ptr + 2).pointee)//33

print(ptr[0])//11
print(ptr[1])//22
print(ptr[2])//33

ptr.deinitialize(count: 3)
ptr.deallocate()
class Person{
    var age: Int
    var name: String
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    deinit {
        print(name,"deinit")
    }
}

var ptr = UnsafeMutablePointer<Person>.allocate(capacity: 3)
ptr.initialize(to: Person(age: 10, name: "Jack"))
(ptr + 1).initialize(to: Person(age: 10, name: "Rose"))
(ptr + 2).initialize(to: Person(age: 10, name: "Kate"))
ptr.deinitialize(count: 3)
ptr.deallocate()
//Jack deinit
//Rose deinit
//Kate deinit
  1. 指针之间的转换
  • unsafeBitCast是忽略类型的强制类型转换,不会因为数据类型的变化而改变原来的内存数据 —— 类似于C++中的reinterpret_cast
var ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)

ptr.assumingMemoryBound(to: Int.self).pointee = 11
(ptr + 8).assumingMemoryBound(to: Double.self).pointee = 22.0//非泛型指针+8 就是偏移8个字节  和泛型指针有区别 注意!

print(unsafeBitCast(ptr, to: UnsafePointer<Int>.self).pointee)//11
print(unsafeBitCast(ptr + 8, to: UnsafePointer<Double>.self).pointee)//22.0

ptr.deallocate()

----

class Person { }
var person = Person()
var ptr = unsafeBitCast(person, to: UnsafeRawPointer.self)
print(ptr)

相关文章

  • 十八、内存访问冲突、指针

    内存访问冲突(Conflicting Access to Memory) 产生内存访问冲突的条件 内存访问冲突会在...

  • Swift十六(1: 内存访问冲突,2: 指针)

    1 内存访问冲突2 swift指针 一: 内存访问冲突 内存访问冲突会在两个访问满足下列条件时发生:至少一个是写入...

  • 内存访问冲突、指针

    上面代码是在全局区 _?表示绑定非空的值 v?表示绑定非空的值 is只是用来判断是否是某个类型,as是转成某个类型...

  • 内存访问冲突

    内存访问冲突会在两个访问满足下列条件时发生 不存在内存访问冲突 存在内存访问冲突 解决内存访问冲突 如果下面的条件...

  • 内存访问冲突,指针,逃逸闭包

    swift系列课程 子类继承父类 则子类的访问级别小于等于父类 子类成员重写 则子类重写成员要么大于等于子类访问级...

  • 指针

    空指针 空指针 指向内存中 编号为0的空间 用于初始化 指针变量 空指针指向的内存是不可访问的 野指针 指针变量 ...

  • Swift5.0 - day8-内存访问冲突、指针

    一、内存访问冲突 1.1、内存访问冲突会在两个访问满足下列条件时发生(1)、至少一个是写入操作(2)、它们访问的是...

  • 2017.9.14

    对象数组,指针,内存访问方式通过变量名地址访问,地址运算符,&、指针变量 概念,动态存储分配

  • Swift 中的内存安全性

    内存安全 inout 参数访问冲突 在函数体内,同时读、写 stepSize 这块内存区域。 inout 参数访问...

  • 7 指针

    指针的作用,可以通过指针间接访问内存。可以用指针变量报错内存地址,用16进制表示 如上,我们定义指针变量类型需要和...

网友评论

      本文标题:十八、内存访问冲突、指针

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