在 for 循环中使用日期格式化程序的 dateFromString api 会产生巨大的内存问题
Using dateFromString api of date formatter in a for loop giving huge memory issues
我在 for 循环之外创建了一个 NSDateFormatter
的实例(或者可以说是一个实例变量),然后在 for 循环中将其用作 [dateFormatter dateFromString]
。这给我带来了巨大的记忆问题。我尝试使用 @autorelease
指令降低巨大的内存分配,我已将 for 循环移动到自动释放块。此外,我在自动释放块之外将 dateFormatter 实例设置为 nil。正在寻找一种更好的方法来降低由于 for 循环中的 dateFormatter 而导致的内存消耗。
-(void)start {
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:10.0 target: self selector:@selector(refresh) userInfo: nil repeats: YES];
}
-(void)refresh
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// Code for Fetching data from server and parsing it
CustomObject *obj = [Parser parseData:dictionary];
});
}
@implementation Parser
+(CustomObject *)parseData:(NSDictionary *) dictioanry {
NSArray *array;
array = [dictionary objectForKey:@"someKey"];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
@autoreleasepool
{
for ( NSDictionary *dic in array)
{
NSDate *date = [df dateFromString:[dic objectForKey:@"key"]];
nestedObj.startTime = date;
// construct and store the custom Objects
// add the nested objects to an array
[obj.arr add:nestedObj];
date = nil;
}
}
df = nil;
return obj;
}
@end
你的@autoreleasepool
放错地方了。您必须在每个循环结束时排空池:
for ( NSDictionary *dic in array)
{
@autoreleasepool {
NSDate *date = [millisecondDateFormatter dateFromString:[dic objectForKey:@"key"]];
obj.nestedObj.startTime = date;
date = nil;
}
}
也就是说,我假设您的真实代码明显不同。这段代码没有任何意义。您一遍又一遍地覆盖相同的 obj.nestedObj.startTime
。只有最后一次循环迭代才重要。但也许这是您创建示例时的转录错误。
请注意,没有理由像这样到处使用 x = nil
。这将自动发生,您通常应该允许它这样做。
编辑:
只是想在评论中谈谈@trojanfoe 的问题(这里没有什么那么重要,这只是一个有趣的问题)。我们可以稍微探索一下 Foundation,看看它在做什么。几经周折后,对 dateFromString:
的调用最终在一个名为 _getObjectValue:
的方法中结束,该方法最终在 OS X 版本中执行如下操作:
...
NSDate *date = (NSDate *)CFDateFormatterCreateDateFromString(NULL, (CFTypeRef)self, ...);
if (date != nil) { CFMakeCollectable((CFTypeRef)date); }
[date autorelease];
...
考虑到 getObjectValue:forString:range:error:
是最通用的形式,它是一个 dateFromString
引用,我们可以在不深入汇编的情况下凭直觉理解这一点,所以一切都可能通过它成为瓶颈(这在事实真实)。 Swift 对该方法的解释可以让您了解它可能会在某处进行自动释放:
func getObjectValue(_ obj: AutoreleasingUnsafePointer<AnyObject?>, forString string: String!, range rangep: UnsafePointer<NSRange>, error error: NSErrorPointer) -> Bool
当然,在实践中,您几乎从来不会这么认真地考虑这个问题:D 您应该假设您调用的任何 Cocoa 方法都可能生成自动释放的对象,并相应地进行操作。即使您可以证明它不在 Cocoa 的特定版本中,Apple 也可以在未来的版本中自由更改它,因此您应该始终期待它们。
我在 for 循环之外创建了一个 NSDateFormatter
的实例(或者可以说是一个实例变量),然后在 for 循环中将其用作 [dateFormatter dateFromString]
。这给我带来了巨大的记忆问题。我尝试使用 @autorelease
指令降低巨大的内存分配,我已将 for 循环移动到自动释放块。此外,我在自动释放块之外将 dateFormatter 实例设置为 nil。正在寻找一种更好的方法来降低由于 for 循环中的 dateFormatter 而导致的内存消耗。
-(void)start {
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:10.0 target: self selector:@selector(refresh) userInfo: nil repeats: YES];
}
-(void)refresh
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// Code for Fetching data from server and parsing it
CustomObject *obj = [Parser parseData:dictionary];
});
}
@implementation Parser
+(CustomObject *)parseData:(NSDictionary *) dictioanry {
NSArray *array;
array = [dictionary objectForKey:@"someKey"];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZ"];
@autoreleasepool
{
for ( NSDictionary *dic in array)
{
NSDate *date = [df dateFromString:[dic objectForKey:@"key"]];
nestedObj.startTime = date;
// construct and store the custom Objects
// add the nested objects to an array
[obj.arr add:nestedObj];
date = nil;
}
}
df = nil;
return obj;
}
@end
你的@autoreleasepool
放错地方了。您必须在每个循环结束时排空池:
for ( NSDictionary *dic in array)
{
@autoreleasepool {
NSDate *date = [millisecondDateFormatter dateFromString:[dic objectForKey:@"key"]];
obj.nestedObj.startTime = date;
date = nil;
}
}
也就是说,我假设您的真实代码明显不同。这段代码没有任何意义。您一遍又一遍地覆盖相同的 obj.nestedObj.startTime
。只有最后一次循环迭代才重要。但也许这是您创建示例时的转录错误。
请注意,没有理由像这样到处使用 x = nil
。这将自动发生,您通常应该允许它这样做。
编辑:
只是想在评论中谈谈@trojanfoe 的问题(这里没有什么那么重要,这只是一个有趣的问题)。我们可以稍微探索一下 Foundation,看看它在做什么。几经周折后,对 dateFromString:
的调用最终在一个名为 _getObjectValue:
的方法中结束,该方法最终在 OS X 版本中执行如下操作:
...
NSDate *date = (NSDate *)CFDateFormatterCreateDateFromString(NULL, (CFTypeRef)self, ...);
if (date != nil) { CFMakeCollectable((CFTypeRef)date); }
[date autorelease];
...
考虑到 getObjectValue:forString:range:error:
是最通用的形式,它是一个 dateFromString
引用,我们可以在不深入汇编的情况下凭直觉理解这一点,所以一切都可能通过它成为瓶颈(这在事实真实)。 Swift 对该方法的解释可以让您了解它可能会在某处进行自动释放:
func getObjectValue(_ obj: AutoreleasingUnsafePointer<AnyObject?>, forString string: String!, range rangep: UnsafePointer<NSRange>, error error: NSErrorPointer) -> Bool
当然,在实践中,您几乎从来不会这么认真地考虑这个问题:D 您应该假设您调用的任何 Cocoa 方法都可能生成自动释放的对象,并相应地进行操作。即使您可以证明它不在 Cocoa 的特定版本中,Apple 也可以在未来的版本中自由更改它,因此您应该始终期待它们。