单例的销毁

Posted WeaterMr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例的销毁相关的知识,希望对你有一定的参考价值。

单例的代码实现

    static Person *ple ;
    static dispatch_once_t predicate;
    
    dispatch_once(&predicate, ^{
        NSLog(@"2:%ld", predicate);
        ple = [[Person alloc] init];
    });
    

单例的底层实现原理

void dispatch_once(dispatch_once_t *val, dispatch_block_t block{
	dispatch_once_f(val, block, _dispatch_Block_invoke(block));
}
void
dispatch_once_f(dispatch_once_t *val, void *ctxt, dispatch_function_t func)
{
	dispatch_once_gate_t l = (dispatch_once_gate_t)val;

#if !DISPATCH_ONCE_INLINE_FASTPATH || DISPATCH_ONCE_USE_QUIESCENT_COUNTER
	uintptr_t v = os_atomic_load(&l->dgo_once, acquire);
        
        // 状态为 DLOCK_ONCE_DONE 直接返回
	if (likely(v == DLOCK_ONCE_DONE)) {
		return;
	}
#if DISPATCH_ONCE_USE_QUIESCENT_COUNTER
	if (likely(DISPATCH_ONCE_IS_GEN(v))) {
		return _dispatch_once_mark_done_if_quiesced(l, v);
	}
#endif
#endif
        // 第一次进来 获取锁, 原子操作多线程处理
	if (_dispatch_once_gate_tryenter(l)) {
                //执行调用
		return _dispatch_once_callout(l, ctxt, func);
	}
        // 有锁锁住的话 会 等待开锁
	return _dispatch_once_wait(l);
}

分析:

  • 1.内部实现的 val (也就是 static dispatch_once_t predicate ) 这个变量用来获取底层原子性的一个关联。关联一个 uintptr_t 类型 v的一个变量,用来查询。
  • 2.当前的 onceToken是一个全局的静态变量。根据每个单利不同,每个静态变量也不同,为了保证唯一性。
  • 3.已经处理过一次了,就retune返回出去了。
  • 4.当第一次代码执行进来的时候:为了保证线程的安全性把自己锁起来,保证当前任务执行的唯一,防止相同的onceToken进行多次执行。锁住之后进行 block 的调用执行。调用完毕后将锁解开,于此同时会将 v 的值 置为 DLOCK_ONCE_DONE(下次就不会在进入到调用block流程)。
    所以保证了单利的唯一性。

如何销毁 ?

通过上面的分析我们可以得到代码执行一次的原因是由于predicate导致,所以当我们销毁的时候也是操作predicate

1.将对应的变量做成全局的变量

//放到外面声明
    static Person *ple ;
    static dispatch_once_t predicate;

2.添加一个类方法:

+ (void)deallocSM {
    predicate = 0;
    per = nil;
}

单例线程安全吗 ?

_dispatch_once_gate_tryenter(l)
static inline bool
_dispatch_once_gate_tryenter(dispatch_once_gate_t l)
{
	return os_atomic_cmpxchg(&l->dgo_once, DLOCK_ONCE_UNLOCKED,
			(uintptr_t)_dispatch_lock_value_for_self(), relaxed);
}

这里是原子操作,并且对线程操作进行加锁处理。_dispatch_lock_value_for_self 是当前队列中的线程空间锁,防止多线程操作 。防止相同的onceToken进行多次执行。线程安全。

以上是关于单例的销毁的主要内容,如果未能解决你的问题,请参考以下文章

单例的销毁

iOS之深入解析单例的实现和销毁的底层原理

静态对象和全局对象的销毁顺序是啥?

内存泄漏解决方式

性能比较好的单例写法

Spring生命周期详解 + 应用实例