Is it leak safe to just use weak reference of Activity in non-static inner classes? - android-activity

Use reference of Activity in non-static inner classes such as Handler will case memory leak, but if I never use Activity reference directly and just use the weak reference, is any problem?

No it is not... The weak references solves just half the problem... The inner instance keep a reference even if you do nothing (if it's not static)... the unintended reference will keep 'alive' the activity to the garbage collector... So, no, it's not leak safe. Well this is on cases where this inner class runs on a background task or if it's not private and somebody else on the outside can keep a reference to the inner.

Related

Is it reliable to use an unowned(unsafe) reference while the object in question is deinitializing?

Update
To clarify, the access of the object during its deinitialization is not being done in its deinit method explicitly. The object in question has listers that get added to it (closures) and these closures are all executed within the deinit method. It is within these closures that accesses of the object is being performed with unowned references. And it is the replacement of those unowned references with unowned(unsafe) references that results in EXC_BAD_ACCESS' from no longer occuring.
It is these unowned(unsafe) references that I'm referring to when asking if they're safe to use if always executed during the object in question's deinit.
Original
I wrote a lot of code predicated on being able to clean up unowned references in the deinitializers of their unowned object. Lo and behold, that is not a feature of unowned references. But apparently it is of unowned(unsafe) references, at least that is the way it appears to be working right now — what once caused a crash accessing an unowned reference during its object's deinitialization, now is no longer crashing and is working as expected.
If guaranteed that all unowned references will not be accessed after deinitialization of their object, would it be safe to use it?
For more details, the aforementioned cleaning up entails removing the object from a set where the hashability is based off its contents' object identities. So if it's a plain unowned reference, when the set attempts to access its hash, it will crash if that procedure is being performed while the object is already deinitializing.
The reason the objects aren't removed from the set before they are deinitialized is because this code is a component of library that enables the addition of nodes to a directed acyclic graph. As a feature, I decided that I would not require consumers of the library to have to remove the nodes when they're done with them, they can simply add them to the graph, then when they're done, release their object (the node) as they would anyways, and because the library adds listeners onto the nodes to remove them from the graph in their deinitializers, it was anticipated that it wouldn't be a problem — that the graph would be able to be cleaned up transparently. Obviously it's a little more complicated now that it's apparent that unowned(safe) references can't be accessed while the object they're referencing is deinitializing.
If unowned(unsafe) works in the way it appears to, it would be a solution to this problem.
The only difference between unowned(safe) and unowend(unsafe) is that the save variant is implemented using proxy objects and it will reliably crash your app when you access it illegally.
The unsafe variant on the other hand is just a plain C-Style pointer which will sometimes "just work" (if by coincidence the memory has not been reused anyway) and sometimes will strangely crash or just report unpredicable results.
unowned is the same as unowned(safe)
Nevertheless, during deinit you may access all the propertys of your object, see The Documentation
And also:
I am not sure exactly what you have implemented but it looks like you are trying to duplicate the mechanism with tables Swift uses internally for keeping track of deallocations of weak references.
If guaranteed that all unowned references will not be accessed after
deinitialization of their object, would it be safe to use it?
Yes it would be safe. If you have this guarantee I think it would also be simpler to turn all your variables to implicitly unwrapped weak variables.
So if it's a plain unowned reference, when the set attempts to access
its hash, it will crash if that procedure is being performed while the
object is already deinitializing.
Obviously it's a little more complicated now that it's apparent that
unowned(safe) references can't be accessed while the object they're
referencing is deinitializing.
I do not think this is the reason for the crash, the memory is freed after deinitialization, during deinitialization you still have access to the instance to perform any manual cleanup you need, I would suggest to replace the complicated solution that keeps track of deallocated references, and simply rely on Swift to set to nil objects that are deallocated using weak references. If you do not want to refactor you code to handle optionals when make them explicitly unwrapped.
However if during deinitialization you access the object from an other reference(outside deinit) it will fail, this is to ensure consistency. See here that access an instance that is deinitialized will cause an app to crash.

Is reset member function for weak pointers atomic?

If one creates a shared pointer to an object using std::make_shared, and use a weak pointer to it as an observer. When the reference count of the shared pointer hits zero, the object is not deallocated because the weak pointer keeps it alive. (If I am not mistaken here.) Suppose that after a call of member function lock() on that weak pointer, and it turns out that it has expired. Now the programmer wants to call reset() to trigger destruction of the object, because the object is quite large.
The question is: is reset an atomic operation? If the answer is NO, my next question is that why the standard doesn't requires it being atomic.
The object is only deallocated after each weak_ptr that references the object is reset.
You don't modify single weak_ptr from multiple threads, so reset of a single weak_ptr don't need to be atomic.
C++20 introduces a helper class std::atomic, that guarantees, quote
The partial template specialization of std::atomic for std::weak_ptr allows users to manipulate weak_ptr objects atomically.
If multiple threads of execution access the same std::weak_ptr object
without synchronization and any of those accesses uses a non-const
member function of weak_ptr then a data race will occur unless all
such access is performed through an instance of
std::atomic>.
If one is not using C++20, check this SO answer by Chris Jester-Young for workaround.

ARC working method and Necessity of Strong, Weak and UnOwned references

I was facing problem with deallocation of View Controller in my code, then I read about how ARC work and about Strong, Weak and UnOwned references. I was wondering, why swift has made it so complicated? deallocation problem could be solved using slightly different method than what ARC method does. Here is my method:
We can think dependency between objects as directed graph, and can find an unReachable part of graph from current location using proper(using flags) BFS search(in O(n)), and then we can de-initialise all instances which are in unreachable part of graph. Then we can directly work with strong references and there will be no need for weak or unowned references.
Am I missing something here? May be some performance issue or some limitations. Can someone please give me a reason for necessity of Strong, Weak and UnOwned references or some article/document which can explain reason for above in detail?
This is the official documentation and this is a more entertaining discussion. For the most part ARC stays out of your way, just requiring some hints e.g. when creating closures that reference self but execute in the context of another component.

differences between weak and assign property?

I have few questions.
1)where assign property will take memory as we dont need to release for reducing reference count?
2)what is the difference between auto zero reference and non-auto zero reference?how does it work? how will take memory?
weak applies to objects (they have reference counts and all the stuff), but weak references don't increase refcount. But once the object is deallocated (from anywhere in the code), any weak reference to that object is set to nil. This is extremely useful, because if you use only strong and weak references, you can't end up with an invalid pointer (pointer to an already deallocated object).
assign does absolutely nothing with the reference, it is usually used for ints, floats and other non-object types. You can of course assign an object reference to such a variable, but if the object is deallocated, you will still have a pointer to it's memory (which is garbage now, and will hurt you when you use it).
Your concerns about "memory use" are weird - references don't take memory, object do. But you can't deallocate an object if you are going to use it. The simple rule for beginners is: for objects, use strong references whenever you can. When you have a reason not to use strong reference, use weak (usually for delegates and datasources). For primitive types (int, float, CGRect, ...) use assign, because they are not objects.
assign is like weak but there's no zeroing of the pointer when it leaves the heap. So, it's not as safe as weak.

Using weak reference to check if object is deallocated, in Objective-C

I'm using ARC.
Sometimes I wrote the following code to assert a object should be deallocated:
__weak weakVariableOrProperty = someObject;
....
someObject = nil;
// or someObject = anotherObject;
....
if (weakVariableOrProperty) {
#throw [NSException exceptionWithName:NSInternalInconsistencyException reason:#"Object not deallocated" userInfo:nil];
}
For example, I use this code to check if a view controller is deallocated before creating a new view controller.
I believe that weak variable or weak property is set to nil immediately after last strong variable or property was set to nil or another object.
And this code is working as I expected until now.
Using weak variable or property to check if object is deallocated is a technique commonly used?
Is it possible that this code will cause problem in the future?
I believe that weak variable or weak property is set to nil immediately after last strong variable or property was set to nil or another object.
This is not exactly true, because an object could be autoreleased. In this case, the last strong reference may be gone, but the reference count of the instance would remain positive. In cases like that, the __weak reference would not be nil-ed out until the autorelease process takes place.
Is using weak variable or property to check if object is deallocated a technique commonly used?
I seriously doubt that this technique has gained much popularity, because ARC is a relatively new thing to Objective C. However, the technique appears valid.
Is it possible that this code will cause problem in the future?
This is very hard to guess, because the ARC Specification does not make any specific guarantees about the timing of nil-ing out the references, and because the spec allows compilers to optimize sequences of retain and release messages that they send to ARC objects.
Your explanation code will be prone to a race condition.
The object in weakVariableOrProperty could be released (since it's only referenced by a weak reference) after the if condition has been evaluated. To avoid this, introduce an ordinary variable, set it to weakVariableOrProperty and check it for nil instead.
That said, as #dasblinkenlight says, betting on exactly when an object will be gone is tough. In a reference-counted system you don't know what else is holding onto it. It may go away just after you've checked. You should be able to constrain your environment enough that you know the system's not squirreling things away, but both autorelease and weak references complicate things.
The best way to solve this is simply to have well-defined object lifetimes: view controllers that don't live forever, that you explicitly tell to go away and so on.
So I've tried using this technique to ensure that objects are always deallocated on a background thread. The [dealloc] for some of my classes was moderately heavy weight and could take a long time (10s of ms) which would freeze the main thread ever so slightly.
I decided to add all of these heavy objects to an array before they'd be released on the main thread, and then go through that array later on a backgroundd thread to remove them from the array. The thought was that the array would keep the retainCount alive until it could be removed from the array on the background thread, and then i could guarantee the cost of the [dealloc] wouldn't happen on the main thread.
To do this, i had the code below:
while([objectsToDealloc count] && /* other conditions to prevent infinite loop */){
__weak id ref = [objectsToDealloc lastObject];
[objectsToDealloc removeLastObject];
#synchronized(ref){
// synchronising on ref will retain it if possible.
// so if its still around,that means we didn't dealloc it
// like we were asked to.
// so insert it back into our array. once the object is deallocd
// it won't be able to be synchronized, because the weak ref will
// be nil
if(ref){
[objectsToDealloc insertObject:ref atIndex:0];
}
}
}
The idea was that if the array didn't contain the last reference (or if there were pending autoreleases on the object, etc), then the weak ref wouldn't nil out. I'd then #synchronize on the object - the synchronized block will retain + release whatever object is being synchronized - which would ensure the ref would stay alive during that block. if it was nil, then it'd been dealloced. if it wasn't nil, then i should add it back to the array and check back again later.
After testing with this code over the past few weeks, I cannot recommend this strategy to check for deallocated objects. I haven't tracked down exactly why yet, but very rarely the object will dealloc but the ref won't be nil yet, so i'll be adding an invalid object back into the array.
i've only caught this in the debugger one time, though i have crash logs of it happening a few times. You can see below that "nil" ends up in my array, even though the code above should protect against it.
Again, I suggest not using this technique for detecting when/if objects deallocate, and instead focus efforts on clarifying your object graph and relationships.