iOS內存管理方案

__x86_64__環(huán)境調試

TaggedPointer

解析

判斷

static inline bool
_objc_isTaggedPointer(const void * _Nullable ptr)
{
    return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
}
 
ptr&(1UL) == 1UL

取值

value = (ptr^objc_debug_taggedpointer_obfuscator)>>8

NONPOINTER_ISA

解析

判斷class指針==isa

inline Class
objc_object::ISA()
{
    ASSERT(!isTaggedPointer());
#if SUPPORT_INDEXED_ISA
    if (isa.nonpointer) {
        uintptr_t slot = isa.indexcls;
        return classForIndex((unsigned)slot);
    }
    return (Class)isa.bits;
#else
    return (Class)(isa.bits & ISA_MASK);
#endif
}

取值

(lldb) p/x ob.class
(Class) $22 = 0x00007fff8e578118 NSObject
 
 
(lldb) p/x ob->isa
(Class) $21 = 0x001dffff8e578119 NSObject
 
 
0000 0000 extra_rc
 
0 has_sidetable_rc
 
0 deallocating
 
0 weakly_referenced
 
1 1101 1 magic
 
111 1111 1111 1111 1000 1110 0101 0111 1000 0001 0001 1 shiftcls
 
0 has_cxx_dtor
 
0 has_assoc
 
1 nonpointer

shiftcls計算出類對象地址

初始化isa

inline void
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor)
{
    ASSERT(!isTaggedPointer());
     
    if (!nonpointer) {
        isa = isa_t((uintptr_t)cls);
    } else {
        ASSERT(!DisableNonpointerIsa);
        ASSERT(!cls->instancesRequireRawIsa());
 
 
        isa_t newisa(0);
 
 
#if SUPPORT_INDEXED_ISA
        ASSERT(cls->classArrayIndex() > 0);
        newisa.bits = ISA_INDEX_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
        newisa.bits = ISA_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.shiftcls = (uintptr_t)cls >> 3;
#endif
 
 
        // This write must be performed in a single store in some cases
        // (for example when realizing a class because other threads
        // may simultaneously try to use the class).
        // fixme use atomics here to guarantee single-store and to
        // guarantee memory order w.r.t. the class index table
        // ...but not too atomic because we don't want to hurt instantiation
        isa = newisa;
    }
}

左移三位得到cls指針

11111111111111110001110010101111000000100011<<3
 
 
>>> hex(int('11111111111110001110010101111000000100011000', 2))
'0xfff8e578118'

散列表

SideTable

struct SideTable {
    spinlock_t slock;
    RefcountMap refcnts;
    weak_table_t weak_table;
 
 
    SideTable() {
        memset(&weak_table, 0, sizeof(weak_table));
    }
 
 
    ~SideTable() {
        _objc_fatal("Do not delete SideTable.");
    }
 
 
    void lock() { slock.lock(); }
    void unlock() { slock.unlock(); }
    void forceReset() { slock.forceReset(); }
 
 
    // Address-ordered lock discipline for a pair of side tables.
 
 
    template<HaveOld, HaveNew>
    static void lockTwo(SideTable *lock1, SideTable *lock2);
    template<HaveOld, HaveNew>
    static void unlockTwo(SideTable *lock1, SideTable *lock2);
};

RefcountMap

template <typename KeyT, typename ValueT,
          typename ValueInfoT = DenseMapValueInfo<ValueT>,
          typename KeyInfoT = DenseMapInfo<KeyT>,
          typename BucketT = detail::DenseMapPair<KeyT, ValueT>>
class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, ValueInfoT, KeyInfoT, BucketT>,
                                     KeyT, ValueT, ValueInfoT, KeyInfoT, BucketT> {
  friend class DenseMapBase<DenseMap, KeyT, ValueT, ValueInfoT, KeyInfoT, BucketT>;
 
 
  // Lift some types from the dependent base class into this class for
  // simplicity of referring to them.
  using BaseT = DenseMapBase<DenseMap, KeyT, ValueT, ValueInfoT, KeyInfoT, BucketT>;
 
 
  BucketT *Buckets;
  unsigned NumEntries;
  unsigned NumTombstones;
  unsigned NumBuckets;
 
....

BucketT

namespace detail {
 
 
// We extend a pair to allow users to override the bucket type with their own
// implementation without requiring two members.
template <typename KeyT, typename ValueT>
struct DenseMapPair : public std::pair<KeyT, ValueT> {
 
 
  // FIXME: Switch to inheriting constructors when we drop support for older
  //        clang versions.
  // NOTE: This default constructor is declared with '{}' rather than
  //       '= default' to work around a separate bug in clang-3.8. This can
  //       also go when we switch to inheriting constructors.
  DenseMapPair() {}
 
 
  DenseMapPair(const KeyT &Key, const ValueT &Value)
      : std::pair<KeyT, ValueT>(Key, Value) {}
 
 
  DenseMapPair(KeyT &&Key, ValueT &&Value)
      : std::pair<KeyT, ValueT>(std::move(Key), std::move(Value)) {}
 
 
  template <typename AltKeyT, typename AltValueT>
  DenseMapPair(AltKeyT &&AltKey, AltValueT &&AltValue,
               typename std::enable_if<
                   std::is_convertible<AltKeyT, KeyT>::value &&
                   std::is_convertible<AltValueT, ValueT>::value>::type * = 0)
      : std::pair<KeyT, ValueT>(std::forward<AltKeyT>(AltKey),
                                std::forward<AltValueT>(AltValue)) {}
 
 
  template <typename AltPairT>
  DenseMapPair(AltPairT &&AltPair,
               typename std::enable_if<std::is_convertible<
                   AltPairT, std::pair<KeyT, ValueT>>::value>::type * = 0)
      : std::pair<KeyT, ValueT>(std::forward<AltPairT>(AltPair)) {}
 
 
  KeyT &getFirst() { return std::pair<KeyT, ValueT>::first; }
  const KeyT &getFirst() const { return std::pair<KeyT, ValueT>::first; }
  ValueT &getSecond() { return std::pair<KeyT, ValueT>::second; }
  const ValueT &getSecond() const { return std::pair<KeyT, ValueT>::second; }
};
 
 
} // end namespace detail

weak_table_t

struct weak_table_t {
    weak_entry_t *weak_entries;
    size_t    num_entries;
    uintptr_t mask;
    uintptr_t max_hash_displacement;
};

weak_entry_t

struct weak_entry_t {
    DisguisedPtr<objc_object> referent;
    union {
        struct {
            // 這里要存儲的是一個weak指針數(shù)組,所以采用哈希算法
            weak_referrer_t *referrers; // 指向referent對象的weak指針數(shù)組
            uintptr_t        out_of_line_ness : 2; // 這里標記是否超過內聯(lián)邊界
            uintptr_t        num_refs : PTR_MINUS_2; // 數(shù)組中已占用的大小
            uintptr_t        mask; // 數(shù)組下標最大值(數(shù)組大小-1)
            uintptr_t        max_hash_displacement; // 最大哈希偏移值
        };
        struct {
            // out_of_line_ness field is low bits of inline_referrers[1]
            weak_referrer_t  inline_referrers[WEAK_INLINE_COUNT];
        };
    };
 
 
    bool out_of_line() {
        return (out_of_line_ness == REFERRERS_OUT_OF_LINE);
    }
 
 
    weak_entry_t& operator=(const weak_entry_t& other) {
        memcpy(this, &other, sizeof(other));
        return *this;
    }
 
 
    weak_entry_t(objc_object *newReferent, objc_object **newReferrer)
        : referent(newReferent)
    {
        inline_referrers[0] = newReferrer;
        for (int i = 1; i < WEAK_INLINE_COUNT; i++) {
            inline_referrers[i] = nil;
        }
    }
};
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 1、內存布局 stack:方法調用 heap:通過alloc等分配對象 bss:未初始化的全局變量等。 data:...
    AKyS佐毅閱讀 1,722評論 0 19
  • 本文中的源代碼來源:需要下載Runtime的源碼,官方的工程需要經(jīng)過大量調試才能使用。這里有處理好的objc4-7...
    shen888閱讀 950評論 0 3
  • 概述 當我們創(chuàng)建一個對象時: 上面這行代碼在棧上創(chuàng)建了hunter指針,并在堆上創(chuàng)建了一個SWHunter對象。目...
    無忘無往閱讀 913評論 0 2
  • 內存管理 內存布局 內存管理方案 數(shù)據(jù)結構 ARC & MRC 引用計數(shù) 弱引用 自動釋放池 循環(huán)引用 1.內存布...
    風月燈閱讀 157評論 0 0
  • 內存布局 stack(棧區(qū)): 方法調用 heap(堆區(qū)):通過alloc等分配的對象 bss:未初始化的全局變量...
    Jimmy_L_Wang閱讀 735評論 1 3

友情鏈接更多精彩內容