Mobile Development 26 min read

Why MMKV Can Stall Your Mobile App and How to Fix It

The article analyzes IO‑intensive bottlenecks in mobile apps, explains how MMKV’s mmap‑based storage, rewrite, and expansion mechanisms cause main‑thread stalls, and presents concrete optimizations such as value comparison before write, pre‑expansion, compression, expiration handling, and proper instance management to dramatically reduce latency.

Baidu Geek Talk
Baidu Geek Talk
Baidu Geek Talk
Why MMKV Can Stall Your Mobile App and How to Fix It

Mobile applications often become IO‑intensive, especially when reading/writing chat messages, short videos, or image caches. When IO load spikes, even simple file operations like open, stat, or access can exceed 10 seconds on the main thread, leading to noticeable jank.

MMKV Overview

MMKV is a high‑performance key‑value component built on mmap. Each MMKV ID creates two 4 KB files (data and CRC). New key‑value pairs are appended to the data file; the latest entry wins, similar to Redis AOF. This design enables fast reads on the main thread but introduces heavy write‑side operations.

When a key already exists, MMKV still appends a new entry, leaving the old data as garbage. If the file cannot accommodate new data, MMKV first attempts to rewrite (deduplicate) the file, then may expand it by doubling its size.

Rewrite and Expansion Costs

Both rewrite and expansion trigger multiple system calls (e.g., msync, ftruncate, lseek, write, munmap, mmap). In IO‑busy scenarios these calls become expensive and can dominate latency.

size_t oldSize = fileSize;
do {
    fileSize *= 2;
} while (lenNeeded + futureUsage >= fileSize);

The rewrite process also performs a msync to flush changes, which is particularly slow when the disk is under load.

Practical Optimizations

Compare before write : Skip the append if the new value equals the existing one. This reduces unnecessary rewrites and expansions.

if ([mmkv getValueSizeForKey:key actualSize:true] != [value length] ||
    ![value isEqualToString:[mmkv getStringForKey:key]]) {
    [mmkv setString:value forKey:key];
}

Pre‑expand during idle time : Insert a placeholder large value once to trigger expansion before the app becomes IO‑heavy, then replace it with the real data, avoiding a second expansion.

MMKV *mmkv = [MMKV mmkvWithID:@"mmkv_id1"];
[mmkv setString:placeholder forKey:@"key1"];
[mmkv setString:realData forKey:@"key1"];

Compress large values : Store big JSON strings or other bulky data compressed with GZIP/LZ4 before writing to MMKV, then decompress on read. Tests show a 9‑11× reduction in size with only a few milliseconds overhead.

GzipOutputStream::Options opt; opt.format = GzipOutputStream::GZIP; opt.compression_level = 5;

Use expiration : MMKV 1.3.0 supports per‑key expiration, automatically cleaning up stale entries and preventing unbounded file growth.

Switch to a database for large collections : For data that exceeds a few megabytes or requires complex queries, use SQLite or another DB instead of MMKV.

Limit the number of MMKV instances : Each ID creates two 4 KB files and consumes virtual memory. Consolidate related keys into fewer instances to reduce file‑handle and memory pressure.

Additional Findings

First‑time writes (from 0 to 1) often trigger an unexpected msync, causing a noticeable stall. Pre‑warming MMKV during low‑IO periods mitigates this effect. Also, opening a new MMKV file incurs open and mkdir calls; subsequent opens are faster.

Large MMKV files (up to 512 MB observed) dramatically increase virtual memory usage, raising OOM risk. Proper key naming (shorter keys) and periodic cleanup are essential.

Conclusion

MMKV provides excellent read‑performance for mobile apps, but careless write patterns—frequent rewrites, unchecked expansions, and storing massive blobs—can reintroduce the very jank it aims to eliminate. By comparing values before writes, pre‑expanding during idle time, compressing large payloads, setting expirations, and avoiding misuse as a general‑purpose database, developers can keep MMKV fast and memory‑efficient.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

iOSAndroidmmapmobile performanceIO optimizationkey-value storageMMKV
Baidu Geek Talk
Written by

Baidu Geek Talk

Follow us to discover more Baidu tech insights.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.