Docs Menu

Reduce Realm File Size - Swift SDK

On this page

  • Overview
  • Key Concept: Realm File Size
  • Avoid Pinning Transactions
  • Threading
  • Dispatch Queues
  • How to Reduce Realm File Size
  • Compact a Realm Asynchronously
  • Make a Compacted Copy
  • When to Reduce Realm File Size
  • Consider iOS File Size Limitations
  • Summary

The size of a Realm Database file is always larger than the total size of the objects stored within it. This architecture enables some of realm's great performance, concurrency, and safety benefits.

Realm writes new data within unused space tracked inside file. In some situations, unused space may comprise a significant portion of a realm file. If file size grows large enough to negatively impact performance, you can compact the realm to reduce its file size.

Tip
Implement Compacting in Your Production Application

Every production application should implement a shouldCompactOnLaunch callback to periodically reduce the realm file size.

Generally, Realm Database takes less space on disk than a comparable SQLite database. Unexpected file growth may be related to App Services referring to outdated data. These factors can affect file size:

  • Pinning transactions
  • Threading
  • Dispatch Queues

When you consider reducing the file size through compacting, there are a couple of things to keep in mind:

  • Compacting can be a resource-intensive operation
  • Compacting can block the UI thread

Because of these factors, you probably don't want to compact a realm every time you open it, but instead want to consider when to compact a realm. This varies based on your application's platform and usage patterns. When deciding when to compact, consider iOS file size limitations.

Realm ties read transaction lifetimes to the memory lifetime of realm instances. Avoid "pinning" old Realm transactions. Use auto-refreshing realms, and wrap the use of Realm APIs from background threads in explicit autorelease pools.

Realm updates the version of your data that it accesses at the start of a run loop iteration. While this gives you a consistent view of your data, it has file size implications.

Imagine this scenario:

  • Thread A: Read some data from a realm, and then block the thread on a long-running operation.
  • Thread B: Write data on another thread.
  • Thread A: The version on the read thread isn't updated. Realm has to hold intermediate versions of the data, growing in file size with every write.

To avoid this issue, call invalidate() on the realm. This tells the realm that you no longer need the objects you've read so far. This frees realm from tracking intermediate versions of those objects. The next time you access it, realm will have the latest version of the objects.

You can also use these two methods to compact your Realm:

When accessing Realm using Grand Central Dispatch, you may see similar file growth. A dispatch queue's autorelease pool may not drain immediately upon executing your code. Realm cannot reuse intermediate versions of the data until the dispatch pool deallocates the realm object. Use an explicit autorelease pool when accessing realm from a dispatch queue.

Realm compacting works by:

  1. Reading the entire contents of the realm file
  2. Writing the contents to a new file at a different location
  3. Replacing the original file

If the file contains a lot of data, this can be an expensive operation.

Use shouldCompactOnLaunch() (Swift) or shouldCompactOnLaunch (Objective-C) on a realm's configuration object to compact a realm. Specify conditions to execute this method, such as:

  • The size of the file on disk
  • How much free space the file contains

For more information about the conditions to execute in the method, see: When to Reduce Realm File Size.

Important
Compacting may not occur

Compacting cannot occur while a realm is being accessed, regardless of any configuration settings.

When you use the Swift async/await syntax to open a realm asynchronously, you can compact a realm in the background.

func testAsyncCompact() async {
let config = Realm.Configuration(shouldCompactOnLaunch: { totalBytes, usedBytes in
// totalBytes refers to the size of the file on disk in bytes (data + free space)
// usedBytes refers to the number of bytes used by data in the file
// Compact if the file is over 100MB in size and less than 50% 'used'
let oneHundredMB = 100 * 1024 * 1024
return (totalBytes > oneHundredMB) && (Double(usedBytes) / Double(totalBytes)) < 0.5
})
do {
// Realm is compacted asynchronously on the first open if the
// configuration block conditions were met.
let realm = try await Realm(configuration: config)
} catch {
// handle error compacting or opening Realm
}
}

Starting with Realm Swift SDK Versions 10.15.0 and 10.16.0, many of the Realm APIs support the Swift async/await syntax. Projects must meet these requirements:

Swift SDK Version
Swift Version Requirement
Supported OS
10.25.0
Swift 5.6
iOS 13.x
10.15.0 or 10.16.0
Swift 5.5
iOS 15.x

You can save a compacted (and optionally encrypted) copy of a realm to another file location with the Realm.writeCopy(toFile:encryptionKey:) method. The destination file cannot already exist.

Important

Avoid calling this method within a write transaction. If called within a write transaction, this method copies the absolute latest data. This includes any uncommitted changes you made in the transaction before this method call.

Compacting a realm can be an expensive operation that can block the UI thread. Your application should not compact every time you open a realm. Instead, try to optimize compacting so your application does it just often enough to prevent the file size from growing too large. If your application runs in a resource-constrained environment, you may want to compact when you reach a certain file size or when the file size negatively impacts performance.

These recommendations can help you start optimizing compaction for your application:

  • Set the max file size to a multiple of your average realm state size. If your average realm state size is 10MB, you might set the max file size to 20MB or 40MB, depending on expected usage and device constraints.
  • As a starting point, compact realms when more than 50% of the realm file size is no longer in use. Divide the currently used bytes by the total file size to determine the percentage of space that is currently used. Then, check for that to be less than 50%. This means that greater than 50% of your realm file size is unused space, and it is a good time to compact. After experimentation, you may find a different percentage works best for your application.

These calculations might look like this in your shouldCompactOnLaunch callback:

// Set a maxFileSize equal to 20MB in bytes
let maxFileSize = 20 * 1024 * 1024
// Check for the realm file size to be greater than the max file size,
// and the amount of bytes currently used to be less than 50% of the
// total realm file size
return (realmFileSizeInBytes > maxFileSize) && (Double(usedBytes) / Double(realmFileSizeInBytes)) < 0.5

Experiment with conditions to find the right balance of how often to compact realm files in your application.

A large realm file can impact the performance and reliability of your app. Any single realm file cannot be larger than the amount of memory your application would be allowed to map in iOS. This limit depends on the device and on how fragmented the memory space is at that point in time.

If you need to store more data, map it over multiple realm files.

  • Realm Database's architecture enables threading-related benefits, but can result in file size growth.
  • Use compacting to manage file size growth.
  • Define conditions for shouldCompactOnLaunch() to compact a realm.
  • Compacting cannot occur if another process is accessing the realm.
  • You can compact a realm in the background when you use async/await syntax.
←  Bundle a Realm File - Swift SDKEncrypt a Realm - Swift SDK →
Give Feedback
© 2022 MongoDB, Inc.

About

  • Careers
  • Investor Relations
  • Legal Notices
  • Privacy Notices
  • Security Information
  • Trust Center
© 2022 MongoDB, Inc.