Environment:
Elements 8.2.88.1871
XCode 7.1 + iOS 9.1 64bit simulator
Firstly, try below code:
public class BigObjectWontLeak{
private NSMutableArray data;
public override void dealloc(){
NSLog("BigObjectWontLeak dealloc!!"); // this will be called immediately when a = null
}
}
public class BigObjectWillLeak{
private NSMutableArray data = new NSMutableArray withCapacity(128); // the only difference
public override void dealloc(){
NSLog("BigObjectWillLeak dealloc!!"); // this will never be called, just try to add breakpoint
}
}
public static class Program
{
public int Main(int argc, AnsiChar** argv)
{
// memory leak test
var a = new BigObjectWontLeak();
a = null;
var b = new BigObjectWillLeak();
b = null;
}
}
I’ve found different object sizes will cause different ARC behaviors, and that’s ok, but the second one is leaked absolutely.
Then I put the test code into an endless loop to prove this leak which can be observed by XCode Instruments easily, and which won’t happen on equivelent objc code.
for(int i = 0; i<1024; ++i){
var a = new BigObject();
a = null;
}
The allocated memory in the loop will be recycled in the future, but the BigObject.dealloc() will never be called even after its memory is recycled. So although it’s not a memory leak strictly, there’s a bug.
This “delayed release” behavior is very different from what the lateast objective-c’s ARC performs, which means I have to take care when use loop or allocate temporary variables. Sometimes an explicit ARP is necessary to solve OOM which is needless in objc.
Maybe it’s by design, but it’s not a good design as what objc/swift does.
“Get recycled” means that memory is freed and can be reused for new objects. Maybe I should say the old objects are destroyed instead of “get recycled”, but no dealloc methods are called so I’m not sure whether old objects are destroyed properly.
I’m just using XCode Instruments to tell this: the “Persistent Bytes” will be reduced after the loop.
So I can’t ensure the dealloc calls without an explicit ARP?
As I said, I need no explicit ARP to get things done in objc/swift, so Elements’ ARC is not good as the objc/swift?
No. as i explained in the other thread, ARC is a very complicated thing, and there ear zlotys of retains and releases and auto-releases going on for what can look like a simple line of code. You cannot always assume no ARP will be involve din a transaction. For example, many/most merited calls will return an unopened reference that’s in the ARP already.
Could we in theory optimize tis one simple corner case you are providing to not touch the ARP, ate the risk of breaking lots off things that work just fine? Sure — but why, the code you’re providing (created an instance and are it right away) is not something use din real life.
So ask again — whats the purpose here, except for having an academic discussion? Nothing is broken.
what’s odd is our generate code dopes the right thing (it gets/expects a retained object, retains it, releases it twice. So those zero out. But for some reason +[NSObject allocWithZone:] already does a second retain — i.e. the object we get back for allocating it already has a retain out of 2, it seems — which we don’t know about and thus ofc don’t compensate for.
I’ll have to pass this to carlo to have a look on compiler level, whats going on here.
very oddly, if i remove the private NSMutableArray data = new NSMutableArray withCapacity(1024/**1024*/);, the then object deallocates fine. It seems that having that field there causes the extra retain somehow,
Cool! But very surprised to see such a high-priority bug is still opened after 2 months…
Anyway, thanks for your overtime work on weekend to confirm my question
I’m also wondering how to print those malloc/retain/release events. Is there a convenient tool to do that?
btw, it seems I’ve also found the cause why an object returned from a method is autoreleasing which is kept alive until the end of an ARP in Elements’ ARC, but it won’t happen in objc’s ARC. I’ll explain it in my previous thread.