郑州市做网站公司,百度推广一个关键词多少钱,wordpress文章批量,工业产品设计与创客实践项目【iOS】—— retain\release实现原理和属性关键字 1. retain\reelase实现原理1.1 retain实现原理1.2 release实现原理 2. 属性关键字2.1 属性关键字的分类2.2 内存管理关键字2.2.1 weak2.2.2 assgin2.3.3 strong和copy 2.4 线程安全的关键字2.5 修饰变量的关键字2.5.1常量const… 【iOS】—— retain\release实现原理和属性关键字 1. retain\reelase实现原理1.1 retain实现原理1.2 release实现原理 2. 属性关键字2.1 属性关键字的分类2.2 内存管理关键字2.2.1 weak2.2.2 assgin2.3.3 strong和copy 2.4 线程安全的关键字2.5 修饰变量的关键字2.5.1常量const2.5.2 static2.5.3 常量extern2.5.4 static与const联合使用2.5.5 extern与const联合使用 1. retain\reelase实现原理
1.1 retain实现原理
首先来看一下retain的源码 ALWAYS_INLINE id
objc_object::rootRetain(bool tryRetain, objc_object::RRVariant variant)
{// 如果是 Tagged Pointer 则直接返回 this (Tagged Pointer 不参与引用计数管理它的内存在栈区由系统处理)if (slowpath(isTaggedPointer())) return (id)this;// 临时变量标记 SideTable 是否加锁bool sideTableLocked false;// 临时变量标记是否需要把引用计数迁移到 SideTable 中bool transcribeToSideTable false;// 记录 objc_object 之前的 isaisa_t oldisa;// 记录 objc_object 修改后的 isaisa_t newisa;// 似乎是原子性操作读取 isa.bits。为取地址oldisa LoadExclusive(isa.bits);if (variant RRVariant::FastOrMsgSend) {// These checks are only meaningful for objc_retain()// They are here so that we avoid a re-load of the isa.// 这些检查仅对objc_retain()有意义// 它们在这里以便我们避免重新加载isa。if (slowpath(oldisa.getDecodedClass(false)-hasCustomRR())) {ClearExclusive(isa.bits);if (oldisa.getDecodedClass(false)-canCallSwiftRR()) {return swiftRetain.load(memory_order_relaxed)((id)this);}return ((id(*)(objc_object *, SEL))objc_msgSend)(this, selector(retain));}}if (slowpath(!oldisa.nonpointer)) {// a Class is a Class forever, so we can perform this check once// outside of the CAS loopif (oldisa.getDecodedClass(false)-isMetaClass()) {ClearExclusive(isa.bits);return (id)this;}}// 循环结束的条件是 slowpath(!StoreExclusive(isa.bits, oldisa.bits, newisa.bits))// StoreExclusive 函数如果 isa.bits 与 oldisa.bits 的内存内容相同则返回 true并把 newisa.bits 复制到 isa.bits// 否则返回 false并把 isa.bits 的内容加载到 oldisa.bits 中。// 即 do-while 的循环条件是指isa.bits 与 oldisa.bits 内容不同如果它们内容不同则一直进行循环// 循环的最终目的就是把 newisa.bits 复制到 isa.bits 中。// return __c11_atomic_compare_exchange_weak((_Atomic(uintptr_t) *)dst,// oldvalue, value, __ATOMIC_RELAXED, __ATOMIC_RELAXED)// _Bool atomic_compare_exchange_weak( volatile A *obj, C* expected, C desired );// 定义于头文件 stdatomic.h// 原子地比较 obj 所指向对象的内存的内容与 expected 所指向的内存的内容若它们相等则以 desired 替换前者进行读修改写操作。// 否则将 obj 所指向的实际内存内容加载到 *expected 进行加载操作。do {// 默认不需要转移引用计数到 SideTabletranscribeToSideTable false;// 赋值给 newisa第一次进来时 isa.bits, oldisa.bits, newisa.bits 三者是完全相同的newisa oldisa;// 如果 newisa 不是优化的 isa (元类的 isa 是原始的 isa (Class cls))if (slowpath(!newisa.nonpointer)) {// 在 mac、arm64e 下不执行任何操作只在 arm64 下执行 __builtin_arm_clrex();// 在 arm64 平台下清除对 isa.bits 的独占访问标记。ClearExclusive(isa.bits);// 如果需要 tryRetain 则调用 sidetable_tryRetain 函数并根据结果返回 this 或者 nil。// 执行此行之前是不需要在当前函数对 SideTable 加锁的// sidetable_tryRetain 返回 false 表示对象已被标记为正在释放// 所以此时再执行 retain 操作是没有意义的所以返回 nil。if (tryRetain) return sidetable_tryRetain() ? (id)this : nil;// 如果不需要 tryRetain 则调用 sidetable_retain()else return sidetable_retain(sideTableLocked);}// dont check newisa.fast_rr; we already called any RR overrides// 不要检查 newisa.fast_rr; 我们已经调用所有 RR 的重载。// 如果 tryRetain 为真并且 objc_object 被标记为正在释放 (newisa.deallocating)则返回 nilif (slowpath(newisa.isDeallocating())) {ClearExclusive(isa.bits);// SideTable 处于加锁状态if (sideTableLocked) {ASSERT(variant RRVariant::Full);// 进行解锁sidetable_unlock();}// 需要 tryRetainif (slowpath(tryRetain)) {return nil;} else {return (id)this;}}// 下面就是 isa 为 nonpointer并且没有被标记为正在释放的对象uintptr_t carry;// bits extra_rc 自增// x86_64 平台下:// # define RC_ONE (1ULL56)// uintptr_t extra_rc : 8// extra_rc 内容位于 56~64 位newisa.bits addc(newisa.bits, RC_ONE, 0, carry); // extra_rc// 如果 carry 为 true表示要处理引用计数溢出的情况if (slowpath(carry)) {// newisa.extra_rc overflowed// 如果 variant 不为 Full// 则调用 rootRetain_overflow(tryRetain) 它的作用就是把 variant 传为 Full// 再次调用 rootRetain 函数目的就是 extra_rc 发生溢出时我们一定要处理if (variant ! RRVariant::Full) {ClearExclusive(isa.bits);return rootRetain_overflow(tryRetain);}// Leave half of the retain counts inline and // prepare to copy the other half to the side table.// 将 retain count 的一半留在 inline并准备将另一半复制到 SideTable.if (!tryRetain !sideTableLocked) sidetable_lock();// 整个函数只有这里把 sideTableLocked 置为 truesideTableLocked true;// 标记需要把引用计数转移到 SideTable 中transcribeToSideTable true;// x86_64 平台下// uintptr_t extra_rc : 8// # define RC_HALF (1ULL7) 二进制表示为: 0b 1000,0000// extra_rc 总共 8 位现在把它置为 RC_HALF表示 extra_rc 溢出newisa.extra_rc RC_HALF;// 把 has_sidetable_rc 标记为 true表示 extra_rc 已经存不下该对象的引用计数// 需要扩张到 SideTable 中newisa.has_sidetable_rc true;}} while (slowpath(!StoreExclusive(isa.bits, oldisa.bits, newisa.bits)));if (variant RRVariant::Full) {if (slowpath(transcribeToSideTable)) {// Copy the other half of the retain counts to the side table.// 复制 retain count 的另一半到 SideTable 中。sidetable_addExtraRC_nolock(RC_HALF);}// 如果 tryRetain 为 false 并且 sideTableLocked 为 true则 SideTable 解锁if (slowpath(!tryRetain sideTableLocked)) sidetable_unlock();} else {ASSERT(!transcribeToSideTable);ASSERT(!sideTableLocked);}// 返回 thisreturn (id)this;
} 我们根据图来看一下retain步骤
若对象是为TaggedPointer小对象无需进行内存管理直接返回。若isa指针没有进过优化 即!newisa.nonpointer成立由于tryRetainfalse直接进入sidetable_retain方法此方法本质是直接操作散列表最后让目标对象的引用计数1判断对象是否正在释放若正在释放则执行dealloc流程释放弱引用表和引用计数表。**若对象的isa经过优化**执行newisa.bits addc(newisa.bits, RC_ONE, 0, carry)即isa的位域extra_rc1且通过变量carry来判断位域extra_rc是否已满如果位域extra_rc已满则执行newisa.extra_rc RC_HALF即将extra_rc满状态的一半拿出来存到extra_rc位域中然后将另一半存储到散列表中执行sidetable_addExtraRC_nolock(RC_HALF)函数
1.2 release实现原理
看一下release的源代码 ALWAYS_INLINE bool objc_object::rootRelease(bool performDealloc, bool handleUnderflow)
{if (isTaggedPointer()) return false;bool sideTableLocked false;isa_t oldisa;isa_t newisa;retry:do {oldisa LoadExclusive(isa.bits);newisa oldisa;if (slowpath(!newisa.nonpointer)) {// 未优化 isaClearExclusive(isa.bits);if (sideTableLocked) sidetable_unlock();// 入参是否要执行 Dealloc 函数如果为 true 则执行 SEL_deallocreturn sidetable_release(performDealloc);}// extra_rc --newisa.bits subc(newisa.bits, RC_ONE, 0, carry); // extra_rc--if (slowpath(carry)) {// donot ClearExclusive()goto underflow;}// 更新 isa 值} while (slowpath(!StoreReleaseExclusive(isa.bits, oldisa.bits, newisa.bits)));if (slowpath(sideTableLocked)) sidetable_unlock();return false;underflow:// 处理下溢从 side table 中借位或者释放newisa oldisa;// 如果使用了 sidetable_rcif (slowpath(newisa.has_sidetable_rc)) {if (!handleUnderflow) {// 调用本函数处理下溢ClearExclusive(isa.bits);return rootRelease_underflow(performDealloc);}// 从 sidetable 中借位引用计数给 extra_rcsize_t borrowed sidetable_subExtraRC_nolock(RC_HALF);if (borrowed 0) {// extra_rc 是计算额外的引用计数0 即表示被引用一次newisa.extra_rc borrowed - 1; // redo the original decrement toobool stored StoreReleaseExclusive(isa.bits, oldisa.bits, newisa.bits);// 保存失败恢复现场重试 if (!stored) {isa_t oldisa2 LoadExclusive(isa.bits);isa_t newisa2 oldisa2;if (newisa2.nonpointer) {uintptr_t overflow;newisa2.bits addc(newisa2.bits, RC_ONE * (borrowed-1), 0, overflow);if (!overflow) {stored StoreReleaseExclusive(isa.bits, oldisa2.bits, newisa2.bits);}}}// 如果还是保存失败则还回 side tableif (!stored) {sidetable_addExtraRC_nolock(borrowed);goto retry;}sidetable_unlock();return false;}else {// Side table is empty after all. Fall-through to the dealloc path.}}// 没有使用 sidetable_rc 或者 sidetable_rc 计数 0 的就直接释放// 如果已经是释放中抛个过度释放错误if (slowpath(newisa.deallocating)) {ClearExclusive(isa.bits);if (sideTableLocked) sidetable_unlock();return overrelease_error();// does not actually return}// 更新 isa 状态newisa.deallocating true;if (!StoreExclusive(isa.bits, oldisa.bits, newisa.bits)) goto retry;if (slowpath(sideTableLocked)) sidetable_unlock();// 执行 SEL_dealloc 事件__sync_synchronize();if (performDealloc) {((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);}return true;
} 我们根据图来看一下release步骤
若对象为TaggedPointer小对象不需要做内存操作直接返回。**若对象的isa没有经过优化**即!newisa.nonpointer成立直接进入sidetable_release方法此方法本质是直接操作散列表最后让目标对象的引用计数-1。判断引用计数是否为0 如果是0则直接执行dealloc流程。若对象的isa经过优化则执行newisa.bits subc(newisa.bits, RC_ONE, 0, )即对象的isa位域extra_rc-1且通过变量carry标识对象的isa的extra_rc是否为0 如果对象的isa的extra_rc0则去访问散列表判断对象在散列表中是否存在引用计数。如果sidetable的引用计数为0对象进行dealloc流程。
2. 属性关键字
属性关键字是用来修饰属性的关键字保证程序的正常执行。
2.1 属性关键字的分类
内存管理有关的关键字weak, assgin, strong, retain, copy线程安全的关键字monatomic atomic访问权限的关键字readonly readwrite。修饰变量的关键字const static extern。
2.2 内存管理关键字
2.2.1 weak
weak将常用来修饰OC对象数据类型修饰的对象释放之后指针会自动置nil这是弱引用的表现。
**在ARC的环境下为了避免循环引用delegate往往是用的是weak修饰。在MRC下使用assgin修饰。**当某个对象不再拥有strong类型的指向的时候对象就会被释放即使还有weak类型的指针指向它weak指针也会被清除。
2.2.2 assgin
assgin常用于非指针变量用于修饰基础数据类型和C的数据类型用于基本数据类型进行复制操作。
asssgin不会修改引用计数也可以用来修饰对象一般不建议如此因为assgin修饰的对象被释放之后指针的地址还存着成为了一个没有指向的野指针垂悬指针。
assgin修饰的基本类型都是基本数据类型基本数据类型分配在栈上栈上的变量是由系统自动管理不会造成野指针以及MRC状态下的循环引用。
eg当对象A通过retain持有了BB的delegate对象是A如果都是强引用则导致互相持有无法正确的释放造成循环引用。
weak和assgin的区别
修饰的对象不同weak修饰OC对象类型的数据assgin修饰的基本数据类型。引用计数两者都不会增加引用计数。释放后结果不同weak修饰的对象释放之后指针自动为nil。assgin修饰的对象释放之后指针仍然存在成为野指针。修饰delegateMRC下assginARC下weak两者都是为了避免循环引用。
2.3.3 strong和copy
strong是常用的修饰符主要用来修饰OC对象类型的数据NSNumberNSStringNSArray、NSDate、NSDictionary、模型类等。 strong是强引用在ARC下等于retain这一点区别于weak。
strong就是指针拷贝浅拷贝内存地址不变只是产生新的指针新的指针和引用对象的指针指向同一个内存地址没有生成新的对象只是多了一个指针。
**注意**由于使用的是一个内存地址当该内存地址存储的内容发生变更的时候导致属性也跟着变更。
同样用于修饰OC对象类型的数据同时在MRC时期用来修饰block因为MRC时期block要从栈区copy到堆区。现在的ARC系统自动给我们做了这个操作。也就是现在使用strong或者copy修饰block都可以。
copy和strong相同点在于都是属于强引用引用计数1但是copy修饰的对象是内存拷贝在引用的时候会生成新的内存地址和指针和引用对象完全没有相同点因此它不会因为引用属性的变更而改变。
copy关键字和strong的区别 **copy**内存拷贝-深拷贝内存地址不同指针地址也不同。 **strong**指针拷贝-浅拷贝内存地址不变指针地址不同。
声明两个copy属性两个strong属性分别为可变和不可变类型
property (nonatomic, strong) NSString *Strstrong;
property (nonatomic, copy) NSString *Strcopy;
property (nonatomic, strong) NSMutableString *MutableStrongstr;
property (nonatomic, copy) NSMutableString *MutableCopystr;1. 不可变对象对属性进行赋值查看两者的区别 - (void)TestModel {//不可变对象对属性赋值NSString *otherString 我是谁;self.Strcopy otherString;self.Strstrong otherString;self.MutableCopystr otherString;self.MutableStrongstr otherString; // 内容NSLog(原字符串%\n normal:copy%strong%\nMutable:copy%strong%, otherString, _Strcopy, _Strstrong, _MutableCopystr, _MutableStrongstr);// 内存地址NSLog(原字符串%p\n normal:copy%pstrong%p\nMutable:copy%pstrong%p, otherString, _Strcopy, _Strstrong, _MutableCopystr, _MutableStrongstr);// 指针地址NSLog(原字符串%p\n normal:copy%pstrong%p\nMutable:copy%pstrong%p, otherString, _Strcopy, _Strstrong, _MutableCopystr, _MutableStrongstr); }由上面可以看出strong修饰的对象在引用一个对象的时候内存地址都是一样的只有指针地址不同copy修饰的对象也是如此。 为什么呢不是说copy修饰的对象是生成一个新的内存地址嘛这里为什么内存地址还是原来的呢用不可变对象对属性进行赋值无论是strong还是copy都是一样的原内存地址不变生成了新的指针地址。
2. 可变对象对属性进行赋值查看strong和copy的区别 - (void)testModel {//可变对象对属性赋值NSMutableString * OriginalMutableStr [NSMutableString stringWithFormat:我已经开始测试了];self.Strcopy OriginalMutableStr;self.Strstrong OriginalMutableStr;self.MutableCopystr OriginalMutableStr;self.MutableStrongstr OriginalMutableStr;[OriginalMutableStr appendFormat:改变了];// 内容NSLog(原字符串%\n normal:copy%strong%\nMutable:copy%strong%,OriginalMutableStr,_Strcopy,_Strstrong,_MutableCopystr,_MutableStrongstr);// 内存地址NSLog(原字符串%p\n normal:copy%pstrong%p\nMutable:copy%pstrong%p,OriginalMutableStr,_Strcopy,_Strstrong,_MutableCopystr,_MutableStrongstr);// 指针地址NSLog(原字符串%p\n normal:copy%pstrong%p\nMutable:copy%pstrong%p,OriginalMutableStr,_Strcopy,_Strstrong,_MutableCopystr,_MutableStrongstr);
}在上面的结果可以看出strong修饰的属性内存地址依然没有改变但是copy修饰的属性内存值产生了变化。 由此得出结论对可变对象赋值 strong 是原地址不变引用计数1浅拷贝。 copy是生成一个新的地址和对象生成一个新指针指向新的内存地址深拷贝。
3. 此时改变OriginalMutableStr的值 [OriginalMutableStr appendFormat:改变了];结论
strong修饰的属性跟着进行改变。由于OriginalMutableStr是可变类型是在原有内存上进行修改指针地址和内存地址都没有改变由于strong修饰的属性虽然指针地址不同但是指针指向的是原内存地址。不同于strongcopy修饰的类型不仅指针地址不同而且指向的内存地址也和OriginalMutableStr不一样所以不会跟着 OriginalMutableStr的改变而改变。
注意的是使用self.Strcopy 和 _Strcopy 来赋值也是两个不一样的结果因为后者没有调用 set 方法而 copy 和 strong 之所以会产生差别就是因为在 set 方法中copy修饰的属性 调用了 _Strcopy [Strcopy copy] 方法。
4. 深浅拷贝
1深浅拷贝的区别
浅拷贝对内存地址的复制两个指针指向同一个地址增加被拷贝对象的引用计数没有发生新的内存分配。
深拷贝目标对象指针和原对象指针指向两片内存空间。不会增加被拷贝对象的引用计数产生新的内存出现两块内存。
总结区别
浅拷贝增加引用计数不产生新的内存。深拷贝不增加引用计数会新分配内存。
2copy关键字影响了对象的可变和不可变属性吗
可变对象(mutable)copy和mutableCopy都是深拷贝不可变对象(immutable)的copy是浅拷贝,mutableCopy是深拷贝copy方法返回的都是不可变对象,若被拷贝对象是可变对象,返回的也是不可变对象。 3NSMutableArray用copy修饰会出现什么问题?
**出现调用可变方法不可控问题会导致程序崩溃。**给Mutable 被声明为copy修饰的属性赋值 过程描述如下
如果赋值过来的是NSMutableArray对象,会对可变对象进行copy操作,拷贝结果是不可变的,那么copy后就是NSArray 如果赋值过来的是NSArray对象, 会对不可变对象进行copy操作,拷贝结果仍是不可变的,那么copy之后仍是NSArray。 所以不论赋值过来的是什么对象,只要对NSMutableArray进行copy操作,返回的对象都是不可变的。 原来属性声明的是NSMutableArray,可能会调用了add或者remove方法拷贝后的结果是不可变对象,所以一旦调用这些方法就会程序崩溃(crash)。
4说说strong和weak的区别是
strong表示指向并拥有该对象修饰的对象引用计数1只要引用计数不为0就不会被销毁weak表示指向但是不拥有该对象修饰的对象引用计数不会增加。无需手动该对象会自行在内存中销毁。
5weak属性修饰的变量如何实现在变量没有强引用后自动置为 nil
runtime维护了一个weak_table _t弱引用表用于存储某个对象的所有weak指针。weak是一个哈希表key是所指对象的的地址value是weak指针的地址的数组。在回收对象的时候根据对象的地址将所有的weak指针地址的数组便利把其中的数据值为nil。
2.4 线程安全的关键字
nonatomic关键字
nonatomic非原子操作不加锁线程执行快但是多个线程同时访问同一属性会出现崩溃。
atomic关键字
atomic原子操作加锁保证setter和getter存取方法的线程安全仅仅对setter和getter方法加锁。因为线程加锁别的线程访问当前属性的时候会先执行完属性当前的操作。
⚠️注意atomic只针对属性的 getter/setter 方法进行加锁所以安全只是针对getter/setter方法来说并不是整个线程安全因为一个属性并不只有 setter/getter 方法例如果一个线程正在getter 或者 setter时有另外一个线程同时对该属性进行release操作如果release先完成会造成crash
2.5 修饰变量的关键字
2.5.1常量const
常量修饰符表示不可变可以用来修饰右边的基本变量和指针变量放在谁的前面修饰谁基本数据变量p指针变量*p。
**const 类型 * 变量名a可以改变指针的指向不能改变指针指向的内容。 **
const放在 * 号的前面约束参数表示*a只读。只能修改地址a,不能通过a修改访问的内存空间。
int x 12;
int new_x 21;
const int *px x;
px new_x; // 改变指针px的指向使其指向变量y
**类型 * const 变量名可以改变指针指向的内容不能改变指针的指向。 **
const放后面约束参数表示a只读不能修改a的地址只能修改a访问的值不能修改参数的地址。
int y 12;
int new_y 21;
int * const py y;
(*py) new_y; // 改变px指向的变量x的值
const和define的区别
使用宏和常量所占的内存差别不大宏定义的是常量常量都放在常量区只会生成一份内存。
缺点
编译时刻宏是预编译const是编译阶段。导致使用宏定义过多的话随着工程越来越大编译速度会越来越慢 宏不做检查不会报编译错误只是替换const会编译检查会报编译错误。
优点
宏可以定义一些函数方法。const不能。
2.5.2 static
定义所修饰的对象只能在当前文件访问不能通过extern来引用
static修饰全局变量只能在本文件中访问,修改全局变量的作用域,生命周期不会改。避免重复定义全局变量单例模式static修饰局部变量
有时希望函数中的局部变量的值在函数调用结束后不消失而继续保留原值即其占用的存储单元不释放在下一次再调用的时候该变量已经有值。这时就应该指定该局部变量为静态变量用关键字 static 进行声明。延长局部变量的生命周期没有改变变量的作用域只在当前作用域有用,程序结束才会销毁。
注意当在对象A里这么写static int i 10; 当A销毁掉之后 这个i还存在当再次alloc init一个A的对象之后 在新对象里 依然可以拿到i 90除非杀死程序 再次进入才能得到i 0。
局部变量只会生成一份内存,只会初始化一次。把它分配在静态存储区该变量在整个程序执行期间不释放其所分配的空间始终存在
- (void)test{// static修饰局部变量1static int age 0;age;NSLog(%d,age);
}
-(void)test2{// static修饰局部变量2static int age 0;age;NSLog(%d,age);
}[self test];
[self test2];
[self test];
[self test2];
[self test];
[self test2];打印 1 1 2 2 3 3
由此可见 变量生命周期延长了作用域没有变。
2.5.3 常量extern
只是用来获取全局变量(包括全局静态变量)的值不能用于定义变量。
查找优先级 先在当前文件查找有没有全局变量没有找到才会去其他文件查找。
#import JMProxy.h
implementation JMProxy
int ageJMProxy 20;
endimplementation TableViewController
- (void)viewDidLoad {[super viewDidLoad];extern int ageJMProxy;NSLog(%d,ageJMProxy);
}
end
⚠️ extern不能用于定义变量。
2.5.4 static与const联合使用
声明一个静态的全局只读常量。开发中声明的全局变量有些不希望外界改动只允许读取。
iOS中staic和const常用使用场景是用来代替宏把一个经常使用的字符串常量定义成静态全局只读变量. // 开发中经常拿到key修改值因此用const修饰key,表示key只读不允许修改。
static NSString * const key name;// 如果 const修饰 *key1,表示*key1只读key1还是能改变。static NSString const *key1 name;
2.5.5 extern与const联合使用
在多个文件中经常使用的同一个字符串常量可以使用extern与const组合 extern与const组合:只需要定义一份全局变量多个文件共享
interface Person : NSObject
extern NSString * const nameKey name;
end#import ViewController.h
interface ViewController ()end
NSString * const nameKey; // 必须用xonst才能访问到 extern与const组合组合修饰的全局变量
文章转载自: http://www.morning.wdshp.cn.gov.cn.wdshp.cn http://www.morning.mnsts.cn.gov.cn.mnsts.cn http://www.morning.zpyxl.cn.gov.cn.zpyxl.cn http://www.morning.wfysn.cn.gov.cn.wfysn.cn http://www.morning.chrbp.cn.gov.cn.chrbp.cn http://www.morning.fwqgy.cn.gov.cn.fwqgy.cn http://www.morning.ybyln.cn.gov.cn.ybyln.cn http://www.morning.jwxnr.cn.gov.cn.jwxnr.cn http://www.morning.htqrh.cn.gov.cn.htqrh.cn http://www.morning.kndyz.cn.gov.cn.kndyz.cn http://www.morning.wnywk.cn.gov.cn.wnywk.cn http://www.morning.nhdmh.cn.gov.cn.nhdmh.cn http://www.morning.fkyqm.cn.gov.cn.fkyqm.cn http://www.morning.hmtft.cn.gov.cn.hmtft.cn http://www.morning.rkrcd.cn.gov.cn.rkrcd.cn http://www.morning.zkpwk.cn.gov.cn.zkpwk.cn http://www.morning.xjqhh.cn.gov.cn.xjqhh.cn http://www.morning.ydxg.cn.gov.cn.ydxg.cn http://www.morning.nqgjn.cn.gov.cn.nqgjn.cn http://www.morning.qjlkp.cn.gov.cn.qjlkp.cn http://www.morning.zwzwn.cn.gov.cn.zwzwn.cn http://www.morning.wjfzp.cn.gov.cn.wjfzp.cn http://www.morning.jpbpc.cn.gov.cn.jpbpc.cn http://www.morning.xbnkm.cn.gov.cn.xbnkm.cn http://www.morning.xqkjp.cn.gov.cn.xqkjp.cn http://www.morning.ykgkh.cn.gov.cn.ykgkh.cn http://www.morning.nzkkh.cn.gov.cn.nzkkh.cn http://www.morning.bpmtq.cn.gov.cn.bpmtq.cn http://www.morning.tktyh.cn.gov.cn.tktyh.cn http://www.morning.jlxqx.cn.gov.cn.jlxqx.cn http://www.morning.qjlkp.cn.gov.cn.qjlkp.cn http://www.morning.dhbyj.cn.gov.cn.dhbyj.cn http://www.morning.jkszt.cn.gov.cn.jkszt.cn http://www.morning.xcjwm.cn.gov.cn.xcjwm.cn http://www.morning.kpgms.cn.gov.cn.kpgms.cn http://www.morning.fxzw.cn.gov.cn.fxzw.cn http://www.morning.zlchy.cn.gov.cn.zlchy.cn http://www.morning.qkzdc.cn.gov.cn.qkzdc.cn http://www.morning.hbqhz.cn.gov.cn.hbqhz.cn http://www.morning.wxrbl.cn.gov.cn.wxrbl.cn http://www.morning.tbqdm.cn.gov.cn.tbqdm.cn http://www.morning.wnkjb.cn.gov.cn.wnkjb.cn http://www.morning.pxlql.cn.gov.cn.pxlql.cn http://www.morning.pqjlp.cn.gov.cn.pqjlp.cn http://www.morning.lwtfx.cn.gov.cn.lwtfx.cn http://www.morning.xjpnq.cn.gov.cn.xjpnq.cn http://www.morning.zfhwm.cn.gov.cn.zfhwm.cn http://www.morning.rwnx.cn.gov.cn.rwnx.cn http://www.morning.hlmkx.cn.gov.cn.hlmkx.cn http://www.morning.yrblz.cn.gov.cn.yrblz.cn http://www.morning.nqcwz.cn.gov.cn.nqcwz.cn http://www.morning.ggtkk.cn.gov.cn.ggtkk.cn http://www.morning.kqbjy.cn.gov.cn.kqbjy.cn http://www.morning.lfpzs.cn.gov.cn.lfpzs.cn http://www.morning.zcqbx.cn.gov.cn.zcqbx.cn http://www.morning.lizpw.com.gov.cn.lizpw.com http://www.morning.gthwr.cn.gov.cn.gthwr.cn http://www.morning.hmwjk.cn.gov.cn.hmwjk.cn http://www.morning.gcysq.cn.gov.cn.gcysq.cn http://www.morning.xrrbj.cn.gov.cn.xrrbj.cn http://www.morning.fkgqn.cn.gov.cn.fkgqn.cn http://www.morning.kfysh.com.gov.cn.kfysh.com http://www.morning.rwwdp.cn.gov.cn.rwwdp.cn http://www.morning.pcngq.cn.gov.cn.pcngq.cn http://www.morning.cthkh.cn.gov.cn.cthkh.cn http://www.morning.tllhz.cn.gov.cn.tllhz.cn http://www.morning.mdgb.cn.gov.cn.mdgb.cn http://www.morning.rkxdp.cn.gov.cn.rkxdp.cn http://www.morning.ylqb8.cn.gov.cn.ylqb8.cn http://www.morning.qckwj.cn.gov.cn.qckwj.cn http://www.morning.hlyfn.cn.gov.cn.hlyfn.cn http://www.morning.ghjln.cn.gov.cn.ghjln.cn http://www.morning.srky.cn.gov.cn.srky.cn http://www.morning.kksjr.cn.gov.cn.kksjr.cn http://www.morning.frmmp.cn.gov.cn.frmmp.cn http://www.morning.xkhhy.cn.gov.cn.xkhhy.cn http://www.morning.dskmq.cn.gov.cn.dskmq.cn http://www.morning.sjjq.cn.gov.cn.sjjq.cn http://www.morning.dwwbt.cn.gov.cn.dwwbt.cn http://www.morning.mxmzl.cn.gov.cn.mxmzl.cn