iOS Memory Usage Increasing, Can't Find the Culprit

iOS memory usage increasing, can't find the culprit

According to the memory monitor in Xcode, this is causing unbounded memory growth (and eventually memory warnings and force quits) - but profiling the memory usage using the allocations instrument shows the memory usage to be stable.

Believe Instruments and the Allocations information - not the memory monitor in Xcode. The memory monitor graph is completely irrelevant. Ignore it.

This is not because the memory monitor in Xcode is useless or wrong. It is because memory management is completely different for a debug build than for a release build (Instruments uses a release build). This is especially true in Swift (you don't say whether you're using Swift).

Observe memory usage only on the device and only in a release build. Otherwise, you'll be completely misled.

iOS Memory usage keep increasing

Use Heapshot to find memory creep. (see: bbum blog)

Basically, their method is to run the Instruments allocate tool, take a heapshot, run an iteration of your code and another heapshot, repeating 3 or 4 times. This will indicate memory that is allocated and not released during the iterations.

In this case, take a heapshot (called something different now) between downloads.

To figure out the results, disclose to see the individual allocations.

If you need to see where retains, releases, and autoreleases occur for an object use Instruments:

Run in Instruments, in Allocations set "Record reference counts" to on (you will have to stop recording to set the option). Allow the problem code to run, stop recording, then search for the object of interest. After that, you'll need to drill down and you will be able to see where all retains, releases and autoreleases occurred.

Sample Image

Memory leak: steady increase in memory usage with simple device motion logging

First, see this answer of mine:

https://stackoverflow.com/a/28566113/341994

You should not be looking at the Memory graphs in the debugger; believe only what Instruments tells you. Debug builds and Release builds are memory-managed very differently in Swift.

Second, if there is still trouble, try wrapping the interior of your handler in an autoreleasepool closure. I do not expect that that would make a difference, however (as this is not a loop), and I do not expect that it will be necessary, as I suspect that using Instruments will reveal that there was never any problem in the first place. However, the autoreleasepool call will make sure that autoreleased objects are not given a chance to accumulate.

Getting memory usage Live/Dirty Bytes in iOS app programmatically (not Resident/Real Bytes)

I found something else, but it seems to work on the device that the previous method didn't work and not work on the device that the previous method did work :-(
Now I need to figure out how to know which one to use. One device is iPhone 5s with iOS 9 and another is iPhone 5s with iOS 11.
I guess I need to test on more veriaty of devices...

I found it here:

https://opensource.apple.com/source/WebKit/WebKit-7603.1.30.1.33/ios/Misc/MemoryMeasure.mm.auto.html

This translated to something like this in Objective-C:

task_vm_info_data_t vmInfo;
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
kern_return_t err = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
if (err != KERN_SUCCESS)
return 0;

NSLog(@"Memory in use vmInfo.internal (in bytes): %u", vmInfo.internal);

return vmInfo.internal;

I think if I add vmInfo.internal and vmInfo.compressed then I'll get the right result (matching what Xcode Debug navigator is showing)

It looks right for these two devices so far, and 2 other devices I tested.

So my final code looks like this:

task_vm_info_data_t info;
mach_msg_type_number_t size = TASK_VM_INFO_COUNT;
kern_return_t kerr = task_info(mach_task_self(),
TASK_VM_INFO,
(task_info_t)&info,
&size);
if( kerr == KERN_SUCCESS ) {
mach_vm_size_t totalSize = info.internal + info.compressed;
NSLog(@"Memory in use (in bytes): %u", totalSize);
return totalSize;
} else {
NSLog(@"Error with task_info(): %s", mach_error_string(kerr));
}

What is considered high memory usage in an iOS app?

The iPhone 5 has 1GB RAM, the iPhone 4s has 512 MB. iPad 3 had 1GB, iPad 2 has 512MB. Obviously you can't use all of that. You should most definitely not go over 600 MB on the newer devices or over 300 MB on the older devices. Good news: You are far, far below that.

Where high memory usage really hurts: Say you use 600MB on an iPhone 5. Then all other apps that are in RAM can only use 400MB between them. If your app is in the foreground, background apps will be killed, and when the user switches to those apps, they take longer to switch to because they need to be restarted. But if your app goes to the background, it's likely to be killed quickly because it uses so much RAM. And if the user switches to it, starting the app will take long because it uses so much RAM.

As I said, your 18-26 MB is absolutely fine. The user could run 40 apps like that simultaneously on an iPhone 5, or 20 apps on an iPhone 4s.

XCode Instruments 6 (by far) not reflecting the correct amount of memory

The Allocations instrument doesn't record OpenGL ES texture memory allocations. If your app is allocating multiple 32 MB textures, that would explain why Xcode is reporting memory usage of 400 MB and the Allocations instrument is reporting 42 MB.

Use the OpenGL ES Analysis template to look at your texture memory allocations. Use the Allocations instrument to look at the rest of your app's memory allocations.

Find Memory app is using in instrument?

All heap allocations is a more accurate indicator of how much memory your app is using. Keep in mind the Allocations instrument does not measure texture memory so your real memory usage is all heap allocations plus texture memory.

Is the ios iPhone simulator causing memory usage analysis to swell?

I've encountered problems like this when using long running while loops. The problem is that anything that is allocated into the current autorelease pool won't get deallocated until the loop exits.

To guard against this, you can wrap the contents of your while loop in autoreleasepool(invoking:). This will cause each iteration of your loop to have its own autorelease pool that is drained each time.

It would look something like this:

/// Return next line, or nil on EOF.
func nextLine() -> String? {
precondition(fileHandle != nil, "Attempt to read from closed file")

var result: String? = nil

// Read data chunks from file until a line delimiter is found:
while !atEof, result == nil {
result = autoreleasepool {
if let range = buffer.range(of: delimData) {
// Convert complete line (excluding the delimiter) to a string:
let line = String(data: buffer.subdata(in: 0..<range.lowerBound), encoding: encoding)
// Remove line (and the delimiter) from the buffer:
buffer.removeSubrange(0..<range.upperBound)
return line
}
let tmpData = fileHandle.readData(ofLength: chunkSize)
if tmpData.count > 0 {
buffer.append(tmpData)
} else {
// EOF or read error.
atEof = true
if buffer.count > 0 {
// Buffer contains last line in file (not terminated by delimiter).
let line = String(data: buffer as Data, encoding: encoding)
buffer.count = 0
return line
}
}
return nil
}
}
return result
}

As to whether your memory growth is a side effect of the debug environment, it's hard to say. But it would probably be wise to guard against this kind of growth regardless.



Related Topics



Leave a reply



Submit