RLMRealm 数据库如何在 Objective C 中从 25Mb 增长到 11Gb?
How can a RLMRealm database grow from 25Mb to 11Gb in Objective C?
我在我的一个项目中使用了 Realm.io,我在一些 iOS 项目中使用过它,但这是我的第一个 Objective C 桌面应用程序我已经用过它所以这个问题是基于 OS X 的用法。在进一步讨论之前,我认为还值得一提的是测试机是 运行ning El Capitan,所以我知道这是测试版软件。
Realm 作为 CocoaPod 加载,一切正常,我能够 运行 查询等,没有启动问题或其他任何事情让我觉得我可能没有正确关闭我的电话?
我的对象有 2 种主要不同类型,一种用于容纳 'group',另一种用于容纳实际的 'object'。该应用程序是一个照片上传器,因此它读取 Apple 的照片应用程序,索引所有媒体对象和组,然后上传它们。
在第一个 运行 上,或者如果我完全删除领域,那么我们从头开始,一切都过得很快。在接下来的 运行 中,我的查询似乎 运行 变慢了,数据库首先从 25Mb 增加到 50Mb,然后在一个小时后,当我再次检查时,我的数据大约是 11Gb。
我对 Realm 的主要用途是在单例中,但我正在执行一个后台队列,该队列为每个对象排队一个新作业,因此当它发现一张照片时,它会排队另一个作业以检查它是否存在于数据库中,并且如果没有创建它,如果它创建它更新任何现有信息。除非我在作业中声明 Realm 否则我会收到线程错误,因此每次都会定义它。
下面是我的一个调用示例,任何人都可以提出一些我可能做错的事情,或者无论如何都可以控制或压缩数据库的大小,现在它太大了?
- (void)saveMediaObject:(MLMediaObject *)mediaObject mediaGroup:(MLMediaGroup *)mediaGroup
{
[jobQueue addOperationWithBlock:
^{
NSLog(@"saveMediaObject");
lastScanResult = [NSDate date];
RLMRealm *realm = [RLMRealm defaultRealm];
SPMediaObject *spMediaObject = [SPMediaObject objectInRealm:realm forPrimaryKey:[mediaObject identifier]];
if(spMediaObject == nil)
{
spMediaObject = [[SPMediaObject alloc] init];
spMediaObject.identifier = [mediaObject identifier];
}
[realm beginWriteTransaction];
spMediaObject.lastSeen = [NSDate date];
spMediaObject.versionURL = [[mediaObject URL] path];
spMediaObject.versionMimeType = [self mimeTypeForExtension:[[spMediaObject.versionURL pathExtension] lowercaseString]];
spMediaObject.originalURL = [[mediaObject originalURL] path];
spMediaObject.originalMimeType = [self mimeTypeForExtension:[[spMediaObject.originalURL pathExtension] lowercaseString]];
if([mediaObject name] != nil)
{
spMediaObject.caption = [mediaObject name];
}
else
{
spMediaObject.caption = @"";
}
[realm addOrUpdateObject:spMediaObject];
[realm commitWriteTransaction];
}];
}
史蒂夫
Realm's docs on file size 应该提供一些关于这里发生的事情以及如何缓解问题的见解:
You should expect a Realm database to take less space on disk than an equivalent
SQLite database. If your Realm file is much larger than you expect, it may be because
you have a RLMRealm
that is
referring to an older version of the data in the database.
In order to give you a consistent view of your data, Realm only updates the
active version accessed at the start of a run loop iteration. This means that if
you read some data from the Realm and then block the thread on a long-running
operation while writing to the Realm on other threads, the version is never
updated and Realm has to hold on to intermediate versions of the data which you
may not actually need, resulting in the file size growing with each write.
The extra space will eventually be reused by future writes, or may be compacted
— for example by calling writeCopyToPath:error:
.
To avoid this issue you, may call invalidate
to tell Realm that you no longer need any of the objects that you've read from the Realm so far,
which frees us from tracking intermediate versions of those objects. The Realm will update to
the latest version the next time it is accessed.
You may also see this problem when accessing Realm using Grand Central Dispatch.
This can happen when a Realm ends up in a dispatch queue's autorelease pool as
those pools may not be drained for some time after executing your code. The intermediate
versions of data in the Realm file cannot be reused until the
RLMRealm
object is deallocated.
To avoid this issue, you should use an explicit autorelease pool when accessing a Realm
from a dispatch queue.
如果这些建议没有帮助,Realm 工程团队将很乐意分析您的项目以确定最小化文件大小增长的方法。您可以将代码私下发送至 help@realm.io.
我在我的一个项目中使用了 Realm.io,我在一些 iOS 项目中使用过它,但这是我的第一个 Objective C 桌面应用程序我已经用过它所以这个问题是基于 OS X 的用法。在进一步讨论之前,我认为还值得一提的是测试机是 运行ning El Capitan,所以我知道这是测试版软件。
Realm 作为 CocoaPod 加载,一切正常,我能够 运行 查询等,没有启动问题或其他任何事情让我觉得我可能没有正确关闭我的电话?
我的对象有 2 种主要不同类型,一种用于容纳 'group',另一种用于容纳实际的 'object'。该应用程序是一个照片上传器,因此它读取 Apple 的照片应用程序,索引所有媒体对象和组,然后上传它们。
在第一个 运行 上,或者如果我完全删除领域,那么我们从头开始,一切都过得很快。在接下来的 运行 中,我的查询似乎 运行 变慢了,数据库首先从 25Mb 增加到 50Mb,然后在一个小时后,当我再次检查时,我的数据大约是 11Gb。
我对 Realm 的主要用途是在单例中,但我正在执行一个后台队列,该队列为每个对象排队一个新作业,因此当它发现一张照片时,它会排队另一个作业以检查它是否存在于数据库中,并且如果没有创建它,如果它创建它更新任何现有信息。除非我在作业中声明 Realm 否则我会收到线程错误,因此每次都会定义它。
下面是我的一个调用示例,任何人都可以提出一些我可能做错的事情,或者无论如何都可以控制或压缩数据库的大小,现在它太大了?
- (void)saveMediaObject:(MLMediaObject *)mediaObject mediaGroup:(MLMediaGroup *)mediaGroup
{
[jobQueue addOperationWithBlock:
^{
NSLog(@"saveMediaObject");
lastScanResult = [NSDate date];
RLMRealm *realm = [RLMRealm defaultRealm];
SPMediaObject *spMediaObject = [SPMediaObject objectInRealm:realm forPrimaryKey:[mediaObject identifier]];
if(spMediaObject == nil)
{
spMediaObject = [[SPMediaObject alloc] init];
spMediaObject.identifier = [mediaObject identifier];
}
[realm beginWriteTransaction];
spMediaObject.lastSeen = [NSDate date];
spMediaObject.versionURL = [[mediaObject URL] path];
spMediaObject.versionMimeType = [self mimeTypeForExtension:[[spMediaObject.versionURL pathExtension] lowercaseString]];
spMediaObject.originalURL = [[mediaObject originalURL] path];
spMediaObject.originalMimeType = [self mimeTypeForExtension:[[spMediaObject.originalURL pathExtension] lowercaseString]];
if([mediaObject name] != nil)
{
spMediaObject.caption = [mediaObject name];
}
else
{
spMediaObject.caption = @"";
}
[realm addOrUpdateObject:spMediaObject];
[realm commitWriteTransaction];
}];
}
史蒂夫
Realm's docs on file size 应该提供一些关于这里发生的事情以及如何缓解问题的见解:
You should expect a Realm database to take less space on disk than an equivalent SQLite database. If your Realm file is much larger than you expect, it may be because you have a
RLMRealm
that is referring to an older version of the data in the database.In order to give you a consistent view of your data, Realm only updates the active version accessed at the start of a run loop iteration. This means that if you read some data from the Realm and then block the thread on a long-running operation while writing to the Realm on other threads, the version is never updated and Realm has to hold on to intermediate versions of the data which you may not actually need, resulting in the file size growing with each write. The extra space will eventually be reused by future writes, or may be compacted — for example by calling
writeCopyToPath:error:
.To avoid this issue you, may call
invalidate
to tell Realm that you no longer need any of the objects that you've read from the Realm so far, which frees us from tracking intermediate versions of those objects. The Realm will update to the latest version the next time it is accessed.You may also see this problem when accessing Realm using Grand Central Dispatch. This can happen when a Realm ends up in a dispatch queue's autorelease pool as those pools may not be drained for some time after executing your code. The intermediate versions of data in the Realm file cannot be reused until the
RLMRealm
object is deallocated. To avoid this issue, you should use an explicit autorelease pool when accessing a Realm from a dispatch queue.
如果这些建议没有帮助,Realm 工程团队将很乐意分析您的项目以确定最小化文件大小增长的方法。您可以将代码私下发送至 help@realm.io.