在iOS开发中,苹果不建议使用半自动内存管理方式,但不像GC机制一样被禁用,原因是这种半自动内存管理容易在某些情况下导致内存溢出。我们看如下代码:NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
for(int i=0;i<1000000;i++){
NSString *s = @"......";
if(i%1000==0){
//执行代码
}
}
[pool release];
我们这里在循环100万次的代码,每次都创建一个NSString实例,由于NSString没有使用alloc创建实例,因此我们使用了自动回收池,但这里有问题是,这100万个NSString要在for循环完,pool release方法调用后才回收,这就造成for循环调用过程中,内存占用一直上涨。
当然你可以改进上面的代码如下所示:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
for(int i=0;i<1000000;i++){
NSString *s = @"......";
if(i%1000==0){
[pool release];
pool = [[NSAutoreleasePool alloc]init];
}
}
[pool release];
上面代码每循环1000次,就回收自动回收池,然后再紧接着重新创建一个自动回收池给下1000个NSString对象使用。其实这个问题很像Hiberate的一个问题:给你1000万行记录的Excel,让你导入到数据库,你该怎样做呢?直接做法如下所示:
Session session = 获取Hibernate的JDBC连接对象
for(int i =0;i<Excel的行数;i++){
Object obj = 每一行Excel记录对应的JAVA对象;
session.save(obj);
}
Transaction.commit();
由于Hibernate的一级缓存是在你提交事务的时候才清空,并且刷新到数据库上的,因此在循环结束前,你的一级缓存会积累大量obj对象,使得内存专用越来越大。解决方法与Objective-C的自动回收池差不多,就是如下的做法:
Session session = 获取Hibernate的JDBC连接对象
for(int i =0;i<Excel的行数;i++){
Object obj = 每一行Excel记录对应的JAVA对象;
session.save(obj);
for(i%1000==0){
session.flush();
}
}
Transaction.commit();
我们看到每隔1000次就刷新一级缓存,它的作用是清理一级缓存,把数据都发送到数据库上面去,但是我并没有提交事务。也就是数据都从JVM转移到数据库的缓冲区积累了,数据库依然会等待循环结束后的commit()操作才会提交事务。