我正在开发一款至少以3g为目标的ios游戏。我们正在将高清资产用于视网膜显示设备(iphone 4,ipod touch 4th gen)。
记忆方面,Ipod Touch 4th gen似乎是我们最受约束的设备,因为它具有与3gs相同的RAM(256与Iphone 4的512相比),但我们正在使用HD资产。该应用程序曾经在尝试加载100-110mb的ram时崩溃,但现在我们已经降到70MB,我们从来没有加载崩溃。
经过大量的搜索后,似乎没有官方的硬限制,那么我们应该如何知道要使用什么内存预算才能安全?我们希望能够为艺术家提供他们可以使用的预算,而不必担心每张地图的内存问题。
我想你已经回答了自己的问题:尽量不要超过70 Mb的限制,但它真的取决于很多东西:你正在使用的iOS版本(不是SDK),在后台运行的应用程序数量,内存的确切内存你正在使用等
只需避免即时内存飞溅(例如,你使用40 Mb的RAM,然后为一些简短的计算分配80 Mb的更多)。在这种情况下,iOS会立即终止您的应用程序。
您还应该考虑延迟加载资产(仅在您真正需要时才加载它们,而不是事先加载它们)。
使用实用程序Split编写的测试结果(链接在他的回答中):
设备:(崩溃量/总量/总量百分比)
我创建了一个小实用程序,它试图分配尽可能多的内存来崩溃,并记录发生内存警告和崩溃的时间。这有助于找出任何iOS设备的内存预算。
在我的应用程序中,如果使用更多内存,用户体验会更好,所以我必须决定是否真的应该释放didReceiveMemoryWarning
中的所有内存。基于Split和Jasper Pol的答案,使用最多45%的设备总内存似乎是一个安全的门槛(谢谢你们)。
如果有人想看看我的实际实现:
#import "mach/mach.h"
- (void)didReceiveMemoryWarning
{
// Remember to call super
[super didReceiveMemoryWarning];
// If we are using more than 45% of the memory, free even important resources,
// because the app might be killed by the OS if we don't
if ([self __getMemoryUsedPer1] > 0.45)
{
// Free important resources here
}
// Free regular unimportant resources always here
}
- (float)__getMemoryUsedPer1
{
struct mach_task_basic_info info;
mach_msg_type_number_t size = sizeof(info);
kern_return_t kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
if (kerr == KERN_SUCCESS)
{
float used_bytes = info.resident_size;
float total_bytes = [NSProcessInfo processInfo].physicalMemory;
//NSLog(@"Used: %f MB out of %f MB (%f%%)", used_bytes / 1024.0f / 1024.0f, total_bytes / 1024.0f / 1024.0f, used_bytes * 100.0f / total_bytes);
return used_bytes / total_bytes;
}
return 1;
}
斯威夫特(基于this answer):
func __getMemoryUsedPer1() -> Float
{
let MACH_TASK_BASIC_INFO_COUNT = (sizeof(mach_task_basic_info_data_t) / sizeof(natural_t))
let name = mach_task_self_
let flavor = task_flavor_t(MACH_TASK_BASIC_INFO)
var size = mach_msg_type_number_t(MACH_TASK_BASIC_INFO_COUNT)
var infoPointer = UnsafeMutablePointer<mach_task_basic_info>.alloc(1)
let kerr = task_info(name, flavor, UnsafeMutablePointer(infoPointer), &size)
let info = infoPointer.move()
infoPointer.dealloc(1)
if kerr == KERN_SUCCESS
{
var used_bytes: Float = Float(info.resident_size)
var total_bytes: Float = Float(NSProcessInfo.processInfo().physicalMemory)
println("Used: \(used_bytes / 1024.0 / 1024.0) MB out of \(total_bytes / 1024.0 / 1024.0) MB (\(used_bytes * 100.0 / total_bytes)%%)")
return used_bytes / total_bytes
}
return 1
}
通过分配SPLITS repo,我构建了一个来测试可以分配给Today's Extension的iOS内存
iOSMemoryBudgetTestForExtension
以下是我在iPhone 5s中获得的结果
内存警告10 MB
应用程序崩溃在12 MB
通过这种方式,Apple只允许任何扩展功能发挥其全部潜力。
你应该从WWDC 2010 Session videos观看会话147。这是“iPhone OS上的高级性能优化,第2部分”。 关于内存优化有很多好建议。
一些提示是:
NSAutoReleasePool
s确保您的内存使用不会出现峰值。CGImageSource
。- (float)__getMemoryUsedPer1
{
struct mach_task_basic_info info;
mach_msg_type_number_t size = MACH_TASK_BASIC_INFO;
kern_return_t kerr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &size);
if (kerr == KERN_SUCCESS)
{
float used_bytes = info.resident_size;
float total_bytes = [NSProcessInfo processInfo].physicalMemory;
//NSLog(@"Used: %f MB out of %f MB (%f%%)", used_bytes / 1024.0f / 1024.0f, total_bytes / 1024.0f / 1024.0f, used_bytes * 100.0f / total_bytes);
return used_bytes / total_bytes;
}
return 1;
}
如果一个人将使用TASK_BASIC_INFO_COUNT而不是MACH_TASK_BASIC_INFO,你会得到
kerr == KERN_INVALID_ARGUMENT(4)
我通过设备RAM对Jaspers列表进行排序创建了另一个列表(我使用Split的工具进行了自己的测试并修复了一些结果 - 检查我在Jaspers线程中的注释)。
设备RAM:崩溃的百分比范围
特别案例:
设备RAM可以轻松读取:
[NSProcessInfo processInfo].physicalMemory
根据我的经验,1GB设备使用45%,2 / 3GB设备使用50%,4GB设备使用55%是安全的。 macOS的百分比可能会更大一些。