Where is my AVPlayer memory and how to return it?

I simultaneously play heaps of videos with AVPlayer. To reduce load time, I save the corresponding views in NSCache.

This works great until it reaches a certain number of videos, of which the video just stops playing or even appears.

No warnings about errors, logs or memory. In particular, I listen UIApplicationDidReceiveMemoryWarningNotificationto clear the cache, but this is never accepted.

If I delete the cache, all videos play due to worse performance.

This makes me suspect that it is AVPlayerusing memory from another process (which one?). And when this memory reaches a certain limit, new players stop working.

Is it correct?

If so, is there a way to be notified when this magic limit is reached, to take appropriate measures (for example, clear the cache) to ensure that other media can play?

+4
source share
2 answers

The good news and the bad news is good that you can probably fix this problem, it’s bad, it requires work and is somewhat complicated.

Root problem

, , , iOS , , . , iOS ( OS X) . , , , Unified Buffer Cache (, Google) - UBC .

, , 10 , , . , UBC. , , . , - , , , , ( ). , , , , . - iOS , , ( ) wham, .

, , PhotoScrollerNetwork. , , , - . UBC ( API OS X, iOS). , - , UBC, 50% iOS.

( ) - Apple ? , . ? WWDC 2012 Core iOS ( , , , ). , , , , , , , , . API UBC .

, NSCache - AVPlayer? , , UBC - AVPlayer, , - , iOS.

1) NSData NSCache, , , UBC. [ AV, , .] , .

2) , . , AVPlayer, ​​ . 50% , AVPlayers.

PhotoScrollerNetwork . , , , ( JPEG " " ).

// Data Structure
typedef struct {
    size_t freeMemory;
    size_t usedMemory;
    size_t totlMemory;
    size_t resident_size;
    size_t virtual_size;
} freeMemory;

:

// ubc_threshold_ratio defaults to 0.5f
// Take a big chunk of either free memory or all memory
freeMemory fm       = [self freeMemory:@"Initialize"];
float freeThresh    = (float)fm.freeMemory*ubc_threshold_ratio;
float totalThresh   = (float)fm.totlMemory*ubc_threshold_ratio;
size_t ubc_threshold = lrintf(MAX(freeThresh, totalThresh));
size_t ubc_usage = 0;

// Method on some class to monitor the memory pool
- (freeMemory)freeMemory:(NSString *)msg
{
    // http://stackoverflow.com/questions/5012886
    mach_port_t host_port;
    mach_msg_type_number_t host_size;
    vm_size_t pagesize;
    freeMemory fm = { 0, 0, 0, 0, 0 };

    host_port = mach_host_self();
    host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
    host_page_size(host_port, &pagesize);        

    vm_statistics_data_t vm_stat;

    if (host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) != KERN_SUCCESS) {
        LOG(@"Failed to fetch vm statistics");
    } else {
        /* Stats in bytes */ 
        natural_t mem_used = (vm_stat.active_count +
                              vm_stat.inactive_count +
                              vm_stat.wire_count) * pagesize;
        natural_t mem_free = vm_stat.free_count * pagesize;
        natural_t mem_total = mem_used + mem_free;

        fm.freeMemory = (size_t)mem_free;
        fm.usedMemory = (size_t)mem_used;
        fm.totlMemory = (size_t)mem_total;

        struct task_basic_info info;
        if(dump_memory_usage(&info)) {
            fm.resident_size = (size_t)info.resident_size;
            fm.virtual_size = (size_t)info.virtual_size;
        }

#if MEMORY_DEBUGGING == 1
        LOG(@"%@:   "
            "total: %u "
            "used: %u "
            "FREE: %u "
            "  [resident=%u virtual=%u]", 
            msg, 
            (unsigned int)mem_total, 
            (unsigned int)mem_used, 
            (unsigned int)mem_free, 
            (unsigned int)fm.resident_size, 
            (unsigned int)fm.virtual_size
        );
#endif
    }
    return fm;
}

, ubc_usage, , . , ubc_usage ubc_threadhold , .

PS: freeMemory , - , UBC "", ( ).

+13

NSCache, , , , . NSCache:

NSCache , , . , . , .

, nil , , .

Edit:

, objc.io # 7 NSCache:

NSCache , . - , , , .

+2

All Articles