Swift指针与内存管理

105 阅读2分钟

指针

1、指针不安全

  • 指针是不安全的,
  • 越界
  • 类型不同

2、指针类型

  • typed pointer 指定类型指针
  • raw pointer 未指定类型指针(原生指针)
Swiftoc说明
unsafePointer <T>const T*指针及指向的内容都不可变
unsafeMutablePointer<T>T*指针及其指向内存内容都可变
unsafeRawPointerconst void*指针指向的内存区域未定
unsafeMutableRawPointervoid*同上
unsafeBufferPointer<T>
unsafeMutableBufferPointer<T>
unsafeRawBufferPointer
unsafeMUtableRawBufferPointer

3、原始指针的使用


        print(MemoryLayout<GoodGame>.stride) /// 分配的内存大小

        print(MemoryLayout<GoodGame>.alignment) /// 对齐

        let size = MemoryLayout<GoodGame>.size

        let stride = MemoryLayout<GoodGame>.stride

        let alignment = MemoryLayout<GoodGame>.alignment
        let p = UnsafeMutableRawPointer.allocate(byteCount: 4 * stride, alignment: alignment)
        for i in 0..<4 {
            p.advanced(by: i * stride).storeBytes(of: i*i, as: Int.self)
        }
        for i in 0..<4 {
            let value = p.load(fromByteOffset: i * stride, as: Int.self)
            print("\(i)===\(value)")
        }
        p.deallocate()  /// 清除

4、泛型指针


        var age = 20

        /// 获取当前变量的地址

        withUnsafePointer(to: &age) { ptr in

            print(ptr.pointee + 20)

        }

        /// withUnsafeMutablePointer

        /// 访问

        age = withUnsafePointer(to: &age) { ptr in

            return ptr.pointee + 20

        }
        /// 直接分配内存  分配一块int类型内存空间。

        let tPtr = UnsafeMutablePointer<Int>.allocate(capacity: 3)

/// 初始化

        tPtr[0] = 2

        tPtr[1] = 12

        tPtr.initialize(to: age)

        /// 访问内存的值

        print(tPtr.pointee)

       let a = tPtr.pointee + 20

        /// Deinitializes the specified number of values starting at this pointer.

        /// The region of memory starting at this pointer and covering `count`

        /// instances of the pointer's `Pointee` type must be initialized. After

        /// calling `deinitialize(count:)`, the memory is uninitialized, but still bound to the `Pointee` type.

        /// - Parameter count: The number of instances to deinitialize. `count` must not be negative.

        /// - Returns: A raw pointer to the same address as this pointer. The memory

        ///   referenced by the returned raw pointer is still bound to `Pointee`.

        tPtr.deinitialize(count: 5)

        tPtr.deallocate()

\


        let kp = UnsafeMutablePointer<kosdfp>.allocate(capacity: 2)

        kp.initialize(to: kosdfp())

        kp.advanced(by: MemoryLayout<GoodGame>.stride).initialize(to: kosdfp(good1: true, good4: 20))

        kp.deinitialize(count: 2)

        kp.deallocate()

allocate开辟 initialize初始值 deinitialize 清零 deallocate回收。有创建就要赋值,用完清零,再回收。

  • 解析macho

        var size: UInt = 0

        var ptr = getsectdata("__TEXT", "__swift5_types", &size)

        var mhHeader = _dyld_get_image_header(0)

        var setCommondPtr = getsegbyname("__LINKEDIT") /// 虚拟地址等信息

        var linkBaseAdress: UInt64 = 0

        /// 虚拟内存地址  -  fileoff = 链接或者加载的基地址

        if let vmaddr = setCommondPtr?.pointee.vmaddr, let fileoff = setCommondPtr?.pointee.fileoff {

            linkBaseAdress = vmaddr - fileoff

        }

        

        var offset: UInt64 = 0

        if let unwrapperPtr = ptr {

            let intRepresentaion = UInt64(bitPattern: Int64(Int(bitPattern: unwrapperPtr)))

            offset = intRepresentaion - linkBaseAdress

            print(offset) /// 基地址

        }

        

        let mhHeaderPtr_IntReprensentation = UInt64(bitPattern: Int64(Int(bitPattern: mhHeader)))

/// 首地址 + offset  = 程序运行存放真是内存地址

        var dataLoAdress = mhHeaderPtr_IntReprensentation + offset

//        程序运行存放真是内存地址 指向4字节内容  先转换为指针类型

        var dataLoAdressPtr = withUnsafePointer(to: &dataLoAdress) { return $0 }

//        通过指针类型返回   __swift5_types 中data Lo

        var dataLoContent = UnsafePointer<UInt32>.init(bitPattern: Int(exactly: dataLoAdress) ?? 0)?.pointee

        

        

//        找到描述信息

//typeDescOffset 描述在macho 偏移信息

        let typeDescOffset = UInt64(dataLoContent!) + offset - linkBaseAdress

        //描述在macho偏移信息 加 首地址

        var typeDescAdress = typeDescOffset + mhHeaderPtr_IntReprensentation

        /// datalo

        

        // classDescriptor的指针

        let classDescriptor = UnsafePointer<TargetClassDescriptor>.init(bitPattern: Int(exactly: typeDescAdress) ?? 0)?.pointee

        /// 获取name

        if let name = classDescriptor?.name {

            let nameOffset = Int64(name) + Int64(typeDescOffset) + 8

            print(nameOffset)

            let nameAdress = nameOffset + Int64(mhHeaderPtr_IntReprensentation)

            print(nameAdress)

            if let cChar = UnsafePointer<CChar>.init(bitPattern: Int(nameAdress)){

                print(String(cString: cChar))

            }

        }
  • 思路 类的属性 存放在 TargetClassDescriptor name。描述文件中的name
  • 需要得到ClassDescriptor的指针。ClassDescriptor的指针是由 运行首地址 + 描述在macho偏移信息 中间进行指针偏移与转换。
  • 运行首地址
var mhHeader = _dyld_get_image_header(0)
let mhHeaderPtr_IntReprensentation = UInt64(bitPattern: Int64(Int(bitPattern: mhHeader)))
  • 描述在macho偏移信息__swift5_types中的data lo + 基地址 - 链接或者加载的基地址
var setCommondPtr = getsegbyname("__LINKEDIT") /// 虚拟地址等信息

        var linkBaseAdress: UInt64 = 0

        /// 虚拟内存地址  -  fileoff = 链接或者加载的基地址

        if let vmaddr = setCommondPtr?.pointee.vmaddr, let fileoff = setCommondPtr?.pointee.fileoff {

            linkBaseAdress = vmaddr - fileoff

        }

        

        var offset: UInt64 = 0

        if let unwrapperPtr = ptr {

            let intRepresentaion = UInt64(bitPattern: Int64(Int(bitPattern: unwrapperPtr)))

            offset = intRepresentaion - linkBaseAdress

            print(offset) /// 基地址

        }
/// 首地址 + offset  = 程序运行存放真是内存地址

        var dataLoAdress = mhHeaderPtr_IntReprensentation + offset

//        程序运行存放真是内存地址 指向4字节内容  先转换为指针类型

        var dataLoAdressPtr = withUnsafePointer(to: &dataLoAdress) { return $0 }

//        通过指针类型返回   __swift5_types 中data Lo

        var dataLoContent = UnsafePointer<UInt32>.init(bitPattern: Int(exactly: dataLoAdress) ?? 0)?.pointee
//        找到描述信息

//typeDescOffset 描述在macho 偏移信息 - 链接或者加载的基地址

        let typeDescOffset = UInt64(dataLoContent!) + offset - linkBaseAdress

        //描述在macho偏移信息 加 首地址

        var typeDescAdress = typeDescOffset + mhHeaderPtr_IntReprensentation

5、内存绑定


        /// Unmanaged 用来获取对象内存指针

        let objRawPtr = Unmanaged.passUnretained(t as AnyObject).toOpaque()

\


        /// bind 类型为 HeapObject

        let objPtr = objRawPtr.bindMemory(to: HeapObject.self, capacity: 1)

\


        print(objPtr.pointee)

        print("end")

\


        let kt = kosdfpClass()

\


        let opaquePointer = Unmanaged.passUnretained(kt as AnyObject).toOpaque()

\


        let ttPtr = opaquePointer.bindMemory(to: HeapObject.self, capacity: MemoryLayout.stride(ofValue: kt))

         指针绑定  重新绑定指针

         assumingMemoryBound(to:)

        bindingMempry(to: ,capacity: )

        withMemoryRebound(to: ,capacity: ,body:)

内存管理

引用计数取决于 InlineRefCounts HeapObject中   InlineRefCounts refCounts   -》 InlineRefCounts  -》 RefCounts  模块类 初始化强引用 无主引用 位移,左移33位


                                        size_t requiredSize,

                                        size_t requiredAlignmentMask)

 

 new (object) HeapObject(metadata);

 

 

 // Initialize a HeapObject header as appropriate for a newly-allocated object.

  constexpr HeapObject(HeapMetadata const *newMetadata)

    : metadata(newMetadata)

    , refCounts(InlineRefCounts::Initialized)

  { }

 

 

 public:

   enum Initialized_t { Initialized };

   enum Immortal_t { Immortal };

\


   // RefCounts must be trivially constructible to avoid ObjC++

   // destruction overhead at runtime. Use RefCounts(Initialized)

   // to produce an initialized instance.

   RefCounts() = default;

   

   // Refcount of a new object is 1.

   constexpr RefCounts(Initialized_t)

     : refCounts(RefCountBits(0, 1)) {}

 

 

 SWIFT_ALWAYS_INLINE

   constexpr

   RefCountBitsT(uint32_t strongExtraCount, uint32_t unownedCount)

     : bits((BitsType(strongExtraCount) << Offsets::StrongExtraRefCountShift) |

            (BitsType(1)                << Offsets::PureSwiftDeallocShift) |

            (BitsType(unownedCount)     << Offsets::UnownedRefCountShift))

   { }

 (BitsType(strongExtraCount) << Offsets::StrongExtraRefCountShift)\

 

 shiftAfterField(name)  = (name##Shift + name##BitCount)

 strongExtraCount = 0  << Offsets::StrongExtraRefCountShift   shiftAfterField(IsDeiniting); |

 0 + 1 + 31 + 1 |  33 0x21  0x0010 0001

 1      <<  Offsets::PureSwiftDeallocShift)  PureSwiftDeallocShift = 0; |

 1 << 0 |

 unownedCount = 1  <<  Offsets::UnownedRefCountShift))   shiftAfterField(PureSwiftDealloc);

 1 << 0 + 1 0x01    0x0000 00001  0010 0011
  • 循环引用 unowned weak弱引用 无主引用。 swift_weakinit refcount 0 131 32 3262 63 isimmortal unownedRefCount isDeinitingMask StrongExtraRefCount useSlowRc
    isa
    InlineRefCounts {
      atomic<InlineRefCountBits> {
        strong RC + unowned RC + flags
        OR
        HeapObjectSideTableEntry*
      }
    }
  }

  HeapObjectSideTableEntry {
    SideTableRefCounts {
      object pointer
      atomic<SideTableRefCountBits> {
        strong RC + unowned RC + weak RC + flags
      }
    }   
  }