精华内容
下载资源
问答
  • 主要介绍了vue如何解决循环引用组件报错的问题,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 智能指针循环引用以及如何解决循环引用问题。。。。

    首先咱们先看一个程序(如下):

    #include<iostream>
    #include<memory>
    using namespace std;
    template<class T>
    struct Node
    {
    	Node(T data = T()) :_data(data), Pnext(NULL), Ppre(NULL)
    	{
    	}
    	~Node()
    	{
    		cout << "Call ~Node()" << endl;
    	}
    	shared_ptr<Node> Pnext;
    	shared_ptr<Node> Ppre;
    	T _data;
    };
    void testShared_Ptr()
    {
    	shared_ptr<Node<int>>sp1(new Node<int>(1));
    	shared_ptr<Node<int>>sp2(new Node<int>(2));
    	cout << sp1.use_count() << endl;
    	cout << sp2.use_count() << endl;
    	sp1->Pnext = sp2;
    	sp2->Ppre = sp1;
    	cout << sp1.use_count() << endl;
    	cout << sp2.use_count() << endl;
    }
    int main()
    {
    	testShared_Ptr();                                                                                                                cout<<"testShared_pte()函数运行结束"<<endl;
    	return 0;
    }
    

    我们在testShared_ptr函数里面开辟了两个结点,并分别交给两个Shared_ptr指针保管,我们打印了一下他们的引用计数结果如下图:

    然后我们让sp1和结点node2里面的Ppre共同管理着结点node1(他们共用同一个引用计数),让sp2和node1里面的pNext共通过管理着node2(他们共用同一个引用计数);


    此时我们来看一下两个智能指针的引用计数(如下图):

    他们已经由1变为2了,说明每个结点都有两个智能指针管理着,当我们继续往下执行时,会发现testShared_ptr()函数已经执行结束了,但是结点的析构函数并没有调用,我们开辟的结点,并没有被释放,运行结果如下图:

    通过下图,我们来分析一下为什么这两个结点没有被释放:

    为了解决shared_ptr引起的循环引用问题,我们引入一个weak_ptr指针,他不能单独使用,只能配合shared_ptr使用。

    #include<iostream>
    #include<memory>
    using namespace std;
    template<class T>
    struct Node
    {
    	Node(T data = T()) :_data(data)
    	{
    	}
    	~Node()
    	{
    		cout << "Call ~Node()" << endl;
    	}
    	weak_ptr<Node> Pnext;
    	weak_ptr<Node> Ppre;
    	T _data;
    };
    void testShared_Ptr()
    {
    	shared_ptr<Node<int>>sp1(new Node<int>(1));
    	shared_ptr<Node<int>>sp2(new Node<int>(2));
    	cout << sp1.use_count() << endl;
    	cout << sp2.use_count() << endl;
    	sp1->Pnext = sp2;
    	sp2->Ppre = sp1;
    	cout << sp1.use_count() << endl;
    	cout << sp2.use_count() << endl;
    }
    int main()
    {
    	testShared_Ptr();
    	cout << "testShared_pte()函数运行结束"<<endl;
    	return 0;
    }
    

    我们把第一个代码Node类的成员和构造函数调整了一下,看一下运行结果,还存在循环引用不(结果如下图):

    通过上图我们可以看出,我们开辟的结点已经成功释放了,shared_ptr引起的循环引用已经得到解决了,但是具体是怎么解决的我们来慢慢分析,首先我们先看一下库函数里面的shared_ptr到底是怎么实现的,跟我们模拟实现的到底在哪不一样(分析如下图):



    通过上图我们可以看到他继承了一个Ptr_base的类,这个类里面有一个T类型的_Ptr指针,还有一个负责引用计数的类类型的指针,现在我们去看这个负责引用计数的类是怎么实现的,他都有那些成员变量(如下图):

    从上图我们可得到_ptr_base类里面的是第二个成员变量是一个引用计数的基类的指针,他是一个抽象类,里面有两个long类型的变量uses和weak,从他们的名字看,可以猜测他们一个是shared_ptrd的引用计数,一个是weak_ptr的引用计数,他里面有两个纯虚函数,一个是释放他们所管理的资源的,一个是释放自己的,他有三个派生类,分别对这两个函数进行了定义。可以用基类指针指向他的派生类,来达到用正确的方式去释放他们管理的资源和他本身所占用的资源。

    接下来咱们看一下下面代码干了什么事情:

    	sp1->Pnext = sp2;
    
    	sp2->Ppre = sp1;                                                             
    单步前:

    单步后:

    从上图我们可以看出,_uses并没有增加,而weaks增加了1。模型图如下:



    我们继续单步,当出了testshared_ptr()函数作用域之前,我们看看智能指针如何被释放的,如下图:

    以上就是我对智能指针shared_ptr造成的循环引用的理解,以及底下是如何解决的,如果有不对的地方,还望指出,十分感谢。


    展开全文
  • 只要不是构造函数注入就不会产生循环引用的问题。这是因为:spring 容器对构造函数配置Bean 进行实例化的时候,有一个前提,即 Bean 构造函数入参引用的对象必须已经准备就绪。由于这个机制,如果两个Bean 都循环...

    spring中通过依赖注入的方法来解决类的相互依赖问题!!!

    spring中通过依赖注入的方法来解决类的相互依赖问题!!!

    spring中通过依赖注入的方法来解决类的相互依赖问题!!!

    只要不是构造函数注入就不会产生循环引用的问题。

    这是因为:

    spring 容器对构造函数配置Bean 进行实例化的时候,有一个前提,即 Bean 构造函数入参引用的对象必须已经准备就绪。

    由于这个机制,如果两个Bean 都循环引用,都采用构造函数注入的方式,就会发生类似于线程死锁的循环依赖问题。

    代码示例:

    public class TestA {

    private TestB b;

    public TestA(){

    b = new TestB();

    System.out.println("init A");

    }

    }

    public class TestB {

    private TestA a;

    public TestB(){

    a = new TestA();

    System.out.println("testB init");

    }

    public static void main(String[] args) {

    TestA testA = new TestA();

    }

    }

    运行后日志:

    Exception in thread "main" java.lang.StackOverflowError

    这中情况会导致堆栈溢出

    如果将TestA 稍作如下修改即不会出现报错

    public class TestA {

    private TestB b;

    public TestA(){

    System.out.println("init A");

    }

    public void setB(TestB b){

    this.b = b;

    }

    }

    参考:

    Spring 依赖注入三种方式的实现,及循环依赖问题的解决(源码+XML配置)

    如何解决Java循环依赖的问题

    展开全文
  • 解决block 的循环引用。 2.在MRC 情况下,我们可以使用 __block ClassA *weakSelf=self;来解决block 的循环引用。也就是在MRC下将__weak 换成__block而已,也是告诉不要再block 内部对self 就行retain 了。  

    1.在ARC 情况下,我们可以使用 __weak ClassA *weakSelf=self;来解决block 的循环引用。

    2.在MRC 情况下,我们可以使用  __block ClassA *weakSelf=self;来解决block 的循环引用。也就是在MRC下将__weak 换成__block而已,也是告诉不要再block 内部对self 就行retain 了。

                                                                                   未完待续。。。

    展开全文
  • 稍有常识的人都知道在 iOS 开发时,我们经常会遇到循环引用的问题,比如两个强指针相互引用,但是这种简单的情况作为稍有经验的开发者都会轻松地查找出来。 但是遇到下面这样的情况,如果只看其实现代码,也很难...

    稍有常识的人都知道在 iOS 开发时,我们经常会遇到循环引用的问题,比如两个强指针相互引用,但是这种简单的情况作为稍有经验的开发者都会轻松地查找出来。

    但是遇到下面这样的情况,如果只看其实现代码,也很难仅仅凭借肉眼上的观察以及简单的推理就能分析出其中存在的循环引用问题,更何况真实情况往往比这复杂的多:

    testObject1.object = testObject2;
    testObject1.secondObject = testObject3;
    testObject2.object = testObject4;
    testObject2.secondObject = testObject5;
    testObject3.object = testObject1;
    testObject5.object = testObject6;
    testObject4.object = testObject1;
    testObject5.secondObject = testObject7;
    testObject7.object = testObject2;
    

    上述代码确实是存在循环引用的问题:

    detector-retain-objects

    这一次分享的内容就是用于检测循环引用的框架 FBRetainCycleDetector 我们会分几个部分来分析 FBRetainCycleDetector 是如何工作的:

    1. 检测循环引用的基本原理以及过程
    2. 检测涉及 NSObject 对象的循环引用问题
    3. 检测涉及 Associated Object 关联对象的循环引用问题
    4. 检测涉及 Block 的循环引用问题

    这是四篇文章中的第一篇,我们会以类 FBRetainCycleDetector 的 - findRetainCycles 方法为入口,分析其实现原理以及运行过程。

    简单介绍一下 FBRetainCycleDetector 的使用方法:

    _RCDTestClass *testObject = [_RCDTestClass new];
    testObject.object = testObject;
    
    FBRetainCycleDetector *detector = [FBRetainCycleDetector new];
    [detector addCandidate:testObject];
    NSSet *retainCycles = [detector findRetainCycles];
    
    NSLog(@"%@", retainCycles);
    
    1. 初始化一个 FBRetainCycleDetector 的实例
    2. 调用 - addCandidate: 方法添加潜在的泄露对象
    3. 执行 - findRetainCycles 返回 retainCycles

    在控制台中的输出是这样的:

    2016-07-29 15:26:42.043 xctest[30610:1003493] {(
    		(
    		"-> _object -> _RCDTestClass "
    	)
    )}
    

    说明 FBRetainCycleDetector 在代码中发现了循环引用。

    findRetainCycles 的实现

    在具体开始分析 FBRetainCycleDetector 代码之前,我们可以先观察一下方法 findRetainCycles 的调用栈:

    - (NSSet<NSArray<FBObjectiveCGraphElement *> *> *)findRetainCycles
    └── - (NSSet<NSArray<FBObjectiveCGraphElement *> *> *)findRetainCyclesWithMaxCycleLength:(NSUInteger)length
        └── - (NSSet<NSArray<FBObjectiveCGraphElement *> *> *)_findRetainCyclesInObject:(FBObjectiveCGraphElement *)graphElement stackDepth:(NSUInteger)stackDepth
            └── - (instancetype)initWithObject:(FBObjectiveCGraphElement *)object
                └── - (FBNodeEnumerator *)nextObject
                    ├── - (NSArray<FBObjectiveCGraphElement *> *)_unwrapCycle:(NSArray<FBNodeEnumerator *> *)cycle
                    ├── - (NSArray<FBObjectiveCGraphElement *> *)_shiftToUnifiedCycle:(NSArray<FBObjectiveCGraphElement *> *)array
                    └── - (void)addObject:(ObjectType)anObject;
    

    调用栈中最上面的两个简单方法的实现都是比较容易理解的:

    - (NSSet<NSArray<FBObjectiveCGraphElement *> *> *)findRetainCycles {
    	return [self findRetainCyclesWithMaxCycleLength:kFBRetainCycleDetectorDefaultStackDepth];
    }
    
    - (NSSet<NSArray<FBObjectiveCGraphElement *> *> *)findRetainCyclesWithMaxCycleLength:(NSUInteger)length {
    	NSMutableSet<NSArray<FBObjectiveCGraphElement *> *> *allRetainCycles = [NSMutableSet new];
    	for (FBObjectiveCGraphElement *graphElement in _candidates) {
    		NSSet<NSArray<FBObjectiveCGraphElement *> *> *retainCycles = [self _findRetainCyclesInObject:graphElement
    																						  stackDepth:length];
    		[allRetainCycles unionSet:retainCycles];
    	}
    	[_candidates removeAllObjects];
    
    	return allRetainCycles;
    }
    

    - findRetainCycles 调用了 - findRetainCyclesWithMaxCycleLength: 传入了 kFBRetainCycleDetectorDefaultStackDepth 参数来限制查找的深度,如果超过该深度(默认为 10)就不会继续处理下去了(查找的深度的增加会对性能有非常严重的影响)。

    在 - findRetainCyclesWithMaxCycleLength: 中,我们会遍历所有潜在的内存泄露对象 candidate,执行整个框架中最核心的方法 - _findRetainCyclesInObject:stackDepth:,由于这个方法的实现太长,这里会分几块对其进行介绍,并会省略其中的注释:

    - (NSSet<NSArray<FBObjectiveCGraphElement *> *> *)_findRetainCyclesInObject:(FBObjectiveCGraphElement *)graphElement
    																 stackDepth:(NSUInteger)stackDepth {
    	NSMutableSet<NSArray<FBObjectiveCGraphElement *> *> *retainCycles = [NSMutableSet new];
    	FBNodeEnumerator *wrappedObject = [[FBNodeEnumerator alloc] initWithObject:graphElement];
    
    	NSMutableArray<FBNodeEnumerator *> *stack = [NSMutableArray new];
    
    	NSMutableSet<FBNodeEnumerator *> *objectsOnPath = [NSMutableSet new];
    
    	...
    }
    

    其实整个对象的相互引用情况可以看做一个有向图,对象之间的引用就是图的 Edge,每一个对象就是 Vertex查找循环引用的过程就是在整个有向图中查找环的过程,所以在这里我们使用 DFS 来扫面图中的环,这些环就是对象之间的循环引用。

    文章中并不会介绍 DFS 的原理,如果对 DFS 不了解的读者可以看一下这个视频,或者找以下相关资料了解一下 DFS 的实现。

    接下来就是 DFS 的实现:

    - (NSSet<NSArray<FBObjectiveCGraphElement *> *> *)_findRetainCyclesInObject:(FBObjectiveCGraphElement *)graphElement
    																 stackDepth:(NSUInteger)stackDepth {
    	...
    	[stack addObject:wrappedObject];
    
    	while ([stack count] > 0) {
    		@autoreleasepool {
    			FBNodeEnumerator *top = [stack lastObject];
    			[objectsOnPath addObject:top];
    
    			FBNodeEnumerator *firstAdjacent = [top nextObject];
    			if (firstAdjacent) {
    
    				BOOL shouldPushToStack = NO;
    
    				if ([objectsOnPath containsObject:firstAdjacent]) {
    					NSUInteger index = [stack indexOfObject:firstAdjacent];
    					NSInteger length = [stack count] - index;
    
    					if (index == NSNotFound) {
    						shouldPushToStack = YES;
    					} else {
    						NSRange cycleRange = NSMakeRange(index, length);
    						NSMutableArray<FBNodeEnumerator *> *cycle = [[stack subarrayWithRange:cycleRange] mutableCopy];
    						[cycle replaceObjectAtIndex:0 withObject:firstAdjacent];
    
    						[retainCycles addObject:[self _shiftToUnifiedCycle:[self _unwrapCycle:cycle]]];
    					}
    				} else {
    					shouldPushToStack = YES;
    				}
    
    				if (shouldPushToStack) {
    					if ([stack count] < stackDepth) {
    						[stack addObject:firstAdjacent];
    					}
    				}
    			} else {
    				[stack removeLastObject];
    				[objectsOnPath removeObject:top];
    			}
    		}
    	}
    	return retainCycles;
    }
    

    这里其实就是对 DFS 的具体实现,其中比较重要的有两点,一是使用 nextObject 获取下一个需要遍历的对象,二是对查找到的环进行处理和筛选;在这两点之中,第一点相对重要,因为 nextObject 的实现是调用 allRetainedObjects 方法获取被当前对象持有的对象,如果没有这个方法,我们就无法获取当前对象的邻接结点,更无从谈起遍历了:

    - (FBNodeEnumerator *)nextObject {
    	if (!_object) {
    		return nil;
    	} else if (!_retainedObjectsSnapshot) {
    		_retainedObjectsSnapshot = [_object allRetainedObjects];
    		_enumerator = [_retainedObjectsSnapshot objectEnumerator];
    	}
    
    	FBObjectiveCGraphElement *next = [_enumerator nextObject];
    
    	if (next) {
    		return [[FBNodeEnumerator alloc] initWithObject:next];
    	}
    
    	return nil;
    }
    

    基本上所有图中的对象 FBObjectiveCGraphElement 以及它的子类 FBObjectiveCBlock FBObjectiveCObject和 FBObjectiveCNSCFTimer 都实现了这个方法返回其持有的对象数组。获取数组之后,就再把其中的对象包装成新的 FBNodeEnumerator 实例,也就是下一个 Vertex

    因为使用 - subarrayWithRange: 方法获取的数组中的对象都是 FBNodeEnumerator 的实例,还需要一定的处理才能返回:

      • (NSArray<FBObjectiveCGraphElement *> *)_unwrapCycle:(NSArray<FBNodeEnumerator *> *)cycle
      • (NSArray<FBObjectiveCGraphElement *> *)_shiftToUnifiedCycle:(NSArray<FBObjectiveCGraphElement *> *)array

    - _unwrapCycle: 的作用是将数组中的每一个 FBNodeEnumerator 实例转换成 FBObjectiveCGraphElement

    - (NSArray<FBObjectiveCGraphElement *> *)_unwrapCycle:(NSArray<FBNodeEnumerator *> *)cycle {
    	NSMutableArray *unwrappedArray = [NSMutableArray new];
    	for (FBNodeEnumerator *wrapped in cycle) {
    		[unwrappedArray addObject:wrapped.object];
    	}
    
    	return unwrappedArray;
    }
    

    - _shiftToUnifiedCycle: 方法将每一个环中的元素按照地址递增以及字母顺序来排序,方法签名很好的说明了它们的功能,两个方法的代码就不展示了,它们的实现没有什么值得注意的地方:

    - (NSArray<FBObjectiveCGraphElement *> *)_shiftToUnifiedCycle:(NSArray<FBObjectiveCGraphElement *> *)array {
    	return [self _shiftToLowestLexicographically:[self _shiftBufferToLowestAddress:array]];
    }
    

    方法的作用是防止出现相同环的不同表示方式,比如说下面的两个环其实是完全相同的:

    -> object1 -> object2
    -> object2 -> object1
    

    在获取图中的环并排序好之后,就可以讲这些环 union 一下,去除其中重复的元素,最后返回所有查找到的循环引用了。

    总结

    到目前为止整个 FBRetainCycleDetector 的原理介绍大概就结束了,其原理完全是基于 DFS 算法:把整个对象的之间的引用情况当做图进行处理,查找其中的环,就找到了循环引用。不过原理真的很简单,如果这个 lib 的实现仅仅是这样的话,我也不会写几篇文章来专门分析这个框架,真正让我感兴趣的还是 - allRetainedObjects 方法在各种对象以及 block 中获得它们强引用的对象的过程,这也是之后的文章要分析的主要内容。

    展开全文
  • 循环引用 public class MyObject { public Object ref = null; public static void main(String[] args) { MyObject myObject1 = new MyObject(); MyObject myObject2 = new MyObject(); ...
  • 如何解决循环引用

    千次阅读 2018-05-08 19:13:37
    如果出现循环引用,将会报错导入错误。...例如:在本实例中,exts.py就解决循环引用的问题 db_demo3.py from flask import Flask from models import Article from exts import db import config app =...
  • 跟着大神脚步,你会越来越接近大神
  • 总结了四种解决方案,与君共享 1、使用类方法 @interface TimerTarget : NSObject @property (nonatomic, assign) SEL selector; @property (nonatomic, weak) NSTimer *timer; @property (nonatomic, weak) id ...
  • 先看一个循环依赖问题现象循环依赖其实就是循环引用,也就是两个或则两个以上bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。如下图:如何理解“依赖”呢,在Spring中有:构造器循环依赖...
  • 为什么80%码农都做不了架构师?>>> ...
  • 只要不是构造函数注入就不会产生循环引用的问题。 这是因为: spring 容器对构造函数配置Bean 进行实例化的时候,有一个前提,即 Bean 构造函数入参引用的对象必须已经准备就绪。 由于这个机...
  • Spring 如何解决循环依赖的问题

    万次阅读 多人点赞 2018-03-31 21:35:03
    循环引用。---&gt;即2个或以上bean 互相持有对方,最终形成闭环。 eg:A依赖B,B依赖C,C又依赖A。【注意:这里不是函数循环调用【是个死循环,除非有终结条件】,是对象相互依赖关系】2. Spring中循环依赖...
  • 使用weak_ptr解决循环引用的方法 #include #include #include using namespace std ; template < class T> class Node { public : Node(T num) :value(num) { } ~Node() { cout "~...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 797
精华内容 318
关键字:

如何解决循环引用的问题