美文网首页
swift基础_内存管理

swift基础_内存管理

作者: 李永开 | 来源:发表于2022-04-10 18:05 被阅读0次

    一. 打印一个对象

    我们经常打印对象的内存地址,也从网上看到一个对象占用16个字节,那到底是不是呢?
    让我们先来打印一个对象

    import Foundation
    
    //UnsafeMutableRawPointer.allocate(byteCount: <#T##Int#>, alignment: <#T##Int#>)
    class LYKClass {
        let age: Int = 11
    }
    var lykCls = LYKClass() //0x100b13090
    let p1 = lykCls         //0x100b13090
    let p2 = lykCls         //0x100b13090
    
    print(MemoryLayout<LYKClass>.size)          //8
    print(MemoryLayout<LYKClass>.stride)        //8
    print(class_getInstanceSize(LYKClass.self)) //24 = (Swift.Object)16+Int(8)
    
    let ptr = withUnsafeMutablePointer(to: &lykCls, {$0});
    print(ptr)//0x00000001000081b8
    print(ptr.pointee)//0x100b13090 ->ptr是一个指向lykCls对象的指针,ptr.pointee存的地址是lykCls的地址
    

    使用lldb看下内存结构
    我们看到有一个3好像是引用技术,有一个b是我们的age=11,看起来lykCls使用了24个字节,没有问题

    (lldb) x/4wg 0x100b13090
    0x100b13090: 0x0000000100008158 0x0000000600000003
    0x100b130a0: 0x000000000000000b 0x000c000000000000
    

    二. 挖一挖?

    看起来和网上说的差不多,那我们往下挖一挖
    看源码

    1.
    static HeapObject *_swift_allocObject_(HeapMetadata const *metadata,
                                           size_t requiredSize,
                                           size_t requiredAlignmentMask) {
      assert(isAlignmentMask(requiredAlignmentMask));
      auto object = reinterpret_cast<HeapObject *>(
          swift_slowAlloc(requiredSize, requiredAlignmentMask));
    
      // NOTE: this relies on the C++17 guaranteed semantics of no null-pointer
      // check on the placement new allocator which we have observed on Windows,
      // Linux, and macOS.
      new (object) HeapObject(metadata);
    2.
    struct HeapObject {
      /// This is always a valid pointer to a metadata object.
      HeapMetadata const *__ptrauth_objc_isa_pointer metadata;
    
      SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
    
    #ifndef __swift__
      HeapObject() = default;
    
      // Initialize a HeapObject header as appropriate for a newly-allocated object.
      constexpr HeapObject(HeapMetadata const *newMetadata) 
        : metadata(newMetadata)
        , refCounts(InlineRefCounts::Initialized)
      { }
      
      // Initialize a HeapObject header for an immortal object
      constexpr HeapObject(HeapMetadata const *newMetadata,
                           InlineRefCounts::Immortal_t immortal)
      : metadata(newMetadata)
      , refCounts(InlineRefCounts::Immortal)
      { }
    3.
    #define SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS       \
      InlineRefCounts refCounts
    4.
    typedef RefCounts<InlineRefCountBits> InlineRefCounts;
    5.
    typedef RefCountBitsT<RefCountIsInline> InlineRefCountBits;
    6.
    class RefCountBitsT {
    
      friend class RefCountBitsT<RefCountIsInline>;
      friend class RefCountBitsT<RefCountNotInline>;
      
      static const RefCountInlinedness Inlinedness = refcountIsInline;
    
      typedef typename RefCountBitsInt<refcountIsInline, sizeof(void*)>::Type
        BitsType;
      typedef typename RefCountBitsInt<refcountIsInline, sizeof(void*)>::SignedType
        SignedBitsType;
      typedef RefCountBitOffsets<sizeof(BitsType)>
        Offsets;
    
      BitsType bits;
    

    BitsType bits是RefCountBitsInt<refcountIsInline, sizeof(void)>的typename,所以说bits的大小=sizeof(void)=64
    RefCount整个文件,就是对通过结构体RefCountBitOffsets对bits进行操作。
    下面是RefCountBitOffsets的结构体元素

    struct RefCountBitOffsets<8> {
      /*
       The bottom 32 bits (on 64 bit architectures, fewer on 32 bit) of the refcount
       field are effectively a union of two different configurations:
       
       ---Normal case---
       Bit 0: Does this object need to call out to the ObjC runtime for deallocation
       Bits 1-31: Unowned refcount
       
       ---Immortal case---
       All bits set, the object does not deallocate or have a refcount
       */
      static const size_t PureSwiftDeallocShift = 0;
      static const size_t PureSwiftDeallocBitCount = 1;
      static const uint64_t PureSwiftDeallocMask = maskForField(PureSwiftDealloc);
    
      static const size_t UnownedRefCountShift = shiftAfterField(PureSwiftDealloc);
      static const size_t UnownedRefCountBitCount = 31;
      static const uint64_t UnownedRefCountMask = maskForField(UnownedRefCount);
    
      static const size_t IsImmortalShift = 0; // overlaps PureSwiftDealloc and UnownedRefCount
      static const size_t IsImmortalBitCount = 32;
      static const uint64_t IsImmortalMask = maskForField(IsImmortal);
    
      static const size_t IsDeinitingShift = shiftAfterField(UnownedRefCount);
      static const size_t IsDeinitingBitCount = 1;
      static const uint64_t IsDeinitingMask = maskForField(IsDeiniting);
    
      static const size_t StrongExtraRefCountShift = shiftAfterField(IsDeiniting);
      static const size_t StrongExtraRefCountBitCount = 30;
      static const uint64_t StrongExtraRefCountMask = maskForField(StrongExtraRefCount);
      
      static const size_t UseSlowRCShift = shiftAfterField(StrongExtraRefCount);
      static const size_t UseSlowRCBitCount = 1;
      static const uint64_t UseSlowRCMask = maskForField(UseSlowRC);
    
      static const size_t SideTableShift = 0;
      static const size_t SideTableBitCount = 62;
      static const uint64_t SideTableMask = maskForField(SideTable);
      static const size_t SideTableUnusedLowBits = 3;
    
      static const size_t SideTableMarkShift = SideTableBitCount;
      static const size_t SideTableMarkBitCount = 1;
      static const uint64_t SideTableMarkMask = maskForField(SideTableMark);
    };
    

    从33-62位是强引用计数,通过计算器可以看到lykCls的引用计数是3

    图片.png

    通过函数打印也是3
    print(CFGetRetainCount(lykCls as AnyObject)) //3

    三. 那弱引用呢

    我们使用weak修饰p3

    weak var p3 = lykCls;
    

    通过断点我们可以看到系统创建了一个WeakReference对象,并且调用nativeInit函数,将p3的地址传了进去

    WeakReference *swift::swift_weakInit(WeakReference *ref, HeapObject *value) {
      ref->nativeInit(value);
      return ref;
    }
    

    接下来通过p3的引用计数对象的formWeakReference创建一个HeapObjectSideTableEntry对象side

    void nativeInit(HeapObject *object) {
        auto side = object ? object->refCounts.formWeakReference() : nullptr;
        nativeValue.store(WeakReferenceBits(side), std::memory_order_relaxed);
      }
    

    side的内部结构

    class HeapObjectSideTableEntry {
    std::atomic<HeapObject*> object;  //包裹的对象
    BitsType bits;                                   //强引用信息
    uint32_t weakBits;                          //弱引用信息
    }
    

    p3的内存地址

    (lldb) x/3wg 0x0000000100b14000
    0x100b14000: 0x0000000100008160 0xc000000020200b90
    0x100b14010: 0x000000000000000b
    

    p3的引用计数是:0xc000000020200b90,它是一个HeapObjectSideTableEntry对象的便宜地址

    图片.png

    将62 63位的值 置为0

    图片.png

    左移3位拿到0x101005C80即side的真实地址

    图片.png

    读取0x101005C80,看到了0x0000000600000003强引用地址,

    图片.png

    0x0000000100000002弱引用地址 这块不确定

    相关文章

      网友评论

          本文标题:swift基础_内存管理

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