iOS Development

Memory Management

Michael L. Collard, Ph.D.

Department of Computer Science, The University of Akron

Memory Management

  • More than syntax
  • 40% of development time/effort (?)
  • Impacts architecture and design
  • Problems may not be detected (memory leaks)

Stack: Automatic

{
    int n; // automatic allocation sizeof(int) with name n
    
    
    
    
        
    // automatic deallocation for memory with name n
}

Heap: Requires Management

{
    Object* obj = /* ALLOCATION */;
        
        
        
        
    /* DEALLOCATION */
}
// Variable named obj out of scope

Memory Management

  • Self managed
  • Garbage Collection
  • Smart pointers
  • ARC

Languages

  • C - self managed, primitive types and "object"s on stack or heap
  • C++ - self managed, primitive types and objects on stack or heap, smart pointers
  • Java - garbage collection
  • C#
    • Managed: garbage collection
    • Unmanaged: self-managed

Objective-C

Self Managed

  • Explicit control over allocation and deallocation
  • Uses library or language feature
  • Advantages:
    • Full control over memory process
    • Potential for most efficiency

C/C++ Self-Managed Scenario

{
    struct data* p = malloc(sizeof(struct data));
    
    // use *p
    
    free(p);
}


{
    Object* p = new Object; 

    // use *p... 

    delete p;
}

Library

{
    struct srcml_archive* p = srcml_create_archive();
    
    
    // use *p
    
    
    srcml_free_archive(p);
}

Self-Managed Difficulties

  • Exceptions
  • Convoluted logic
  • Separated allocation and deallocation

More Typical Library Call

// Location A
struct srcml_archive* p = srcml_create_archive();


// great code distance
// Location B
struct srcml_archive* t = p;


// Location C
free(t);  // where t was copied from pointer p at point B

Self-Managed Memory is Difficult

  • Extra code
  • Memory leaks
  • Double frees
  • Issues of ownership

Resource Acquisition is Initialization

class C {
    srcml_archive* p;
public:
    C() : p(0) { p = new srcml_archive(); }
    ~C() { if (p) delete p; }
};
    
// distant part of program
{
    C c;


        
}

Garbage Collection

  • Automatically reclaim memory no longer used
  • Advantages:
    • Much, much easier to program
  • Disadvantages
    • Heap scans
    • Whole app pauses
    • Non-deterministic releases
    • Typically requires more memory then other approaches

Resources

  • Desktop GC not the same as mobile GC due to limited resources
  • GC performance degrades as less memory is available. 2X memory, 70% slower, 3X memory, 17% slower. ref
  • What about Android (which has GC)? memory intensive applications often avoid allocation during critical times

Smart Pointers

{
    std::shared_ptr<srcml_archive> p(new srcml_archive);


    // p's destructor called, and the object is automatically deleted
}


{
    std::shared_ptr<srcml_archive> p(new srcml_archive);

    // some time later
    std::shared_ptr<srcml_archive> p2 = p;

        
    // p and p2's memory only deleted once
}

What is going on?

  • Reference counting or keep careful track of ownership
  • Not used as frequently as it should

MRR in Objective C

  • Manual Retain-Release
  • Uses reference counting (but don't think about this)
  • We will be using ARC instead, but you will see this kind of code still around

MRR-pertinent Methods

  • alloc - allocates chunk of memory from heap (ownership)
  • init - setup of contents of chunk of memory
  • retain - creates ownership (if not original)
  • release - required for every owner. dealloc when final owner releases

Simple MRR

// subtitle:  a partial and incomplete guide
{
    srcml_archive* archive = [[srcml_archive alloc] init];


    // ...


    [archive release]
}

MRR Shared Pointers

{
    srcml_archive* archive1 = [[srcml_archive alloc] init];
    srcml_archive* archive2 = archive1;
    [archive2 retain];
    //...



    [archive2 release]; // dealloc is not called
    [archive1 release]; // dealloc finally called
}

ARC

  • Wait a second, couldn't the compiler figure this out for itself?
  • Automated Reference Counting
  • Keeps track of references to an object
  • Only releases when references are 0

ARC Shared Pointers

{
    srcml_archive* archive1 = [[srcml_archive alloc] init];
    srcml_archive* archive2 = archive1;




     // dealloc called automatically
}

GC vs ARC vs MRR

  • GC works externally on the heap, while ARC is part of your code
  • GC has to handle every situation. ARC is coded just for the code situations that you write
  • ARC can be more efficient (and safer) then MRR
  • Objective-C can use (and we will use) ARC
  • Swift uses ARC