深入理解Android MMKV数据读取机制:从内存到磁盘的全解析(15)

141 阅读13分钟

深入理解Android MMKV数据读取机制:从内存到磁盘的全解析

一、MMKV数据读取概述

1.1 读取流程简介

MMKV的数据读取流程主要包括以下几个关键步骤:

  1. 从内存缓存中快速查找数据
  2. 如果内存中不存在,则从文件映射中读取
  3. 对加密数据进行解密处理
  4. 反序列化数据并返回给调用者

1.2 核心组件

数据读取涉及的核心组件包括:

  • 内存映射文件:通过mmap将文件映射到内存
  • 内存缓存:存储最近访问的数据
  • 数据解析器:解析不同类型的数据
  • 加密模块:对加密数据进行解密

1.3 性能优势

MMKV的读取性能优势主要体现在:

  • 内存映射避免了频繁的磁盘IO
  • 高效的数据结构和算法
  • 支持并发读取
  • 数据缓存机制减少了重复解析

二、Java层读取API

2.1 基础读取方法

// MMKV.java
/**
 * 读取布尔值
 * @param key 键
 * @param defaultValue 默认值
 * @return 存储的布尔值,如果不存在则返回默认值
 */
public boolean getBoolean(String key, boolean defaultValue) {
    // 检查是否为多进程模式
    if (m_isInterProcess) {
        // 多进程模式下,先检查文件是否有更新
        checkLoadData();
    }
    // 调用本地方法读取布尔值
    return nativeGetBool(m_nativeHandle, key, defaultValue);
}

/**
 * 读取int值
 * @param key 键
 * @param defaultValue 默认值
 * @return 存储的int值,如果不存在则返回默认值
 */
public int getInt(String key, int defaultValue) {
    if (m_isInterProcess) {
        checkLoadData();
    }
    // 调用本地方法读取int值
    return nativeGetInt(m_nativeHandle, key, defaultValue);
}

// 其他类型的读取方法类似...

2.2 批量读取方法

// MMKV.java
/**
 * 获取所有键值对
 * @return 包含所有键值对的Map
 */
public Map<String, ?> getAll() {
    if (m_isInterProcess) {
        checkLoadData();
    }
    // 调用本地方法获取所有键值对
    return nativeGetAll(m_nativeHandle);
}

/**
 * 检查是否包含某个键
 * @param key 键
 * @return 如果包含该键则返回true,否则返回false
 */
public boolean containsKey(String key) {
    if (m_isInterProcess) {
        checkLoadData();
    }
    // 调用本地方法检查是否包含键
    return nativeContainsKey(m_nativeHandle, key);
}

2.3 多进程模式下的读取

// MMKV.java
/**
 * 检查并加载最新数据(多进程模式)
 */
private void checkLoadData() {
    if (m_needLoadData) {
        synchronized (this) {
            if (m_needLoadData) {
                // 调用本地方法重新加载数据
                nativeReloadData(m_nativeHandle);
                m_needLoadData = false;
            }
        }
    }
}

三、JNI层数据读取

3.1 JNI方法映射

// Jni.cpp
static JNINativeMethod gMethods[] = {
    // 映射Java层的nativeGetBool方法到C++层的jniGetBool方法
    {"nativeGetBool", "(JLjava/lang/String;Z)Z", (void *) jniGetBool},
    // 映射Java层的nativeGetInt方法到C++层的jniGetInt方法
    {"nativeGetInt", "(JLjava/lang/String;I)I", (void *) jniGetInt},
    // 映射Java层的nativeGetLong方法到C++层的jniGetLong方法
    {"nativeGetLong", "(JLjava/lang/String;J)J", (void *) jniGetLong},
    // 映射Java层的nativeGetFloat方法到C++层的jniGetFloat方法
    {"nativeGetFloat", "(JLjava/lang/String;F)F", (void *) jniGetFloat},
    // 映射Java层的nativeGetDouble方法到C++层的jniGetDouble方法
    {"nativeGetDouble", "(JLjava/lang/String;D)D", (void *) jniGetDouble},
    // 映射Java层的nativeGetString方法到C++层的jniGetString方法
    {"nativeGetString", "(JLjava/lang/String;Ljava/lang/String;)Ljava/lang/String;", (void *) jniGetString},
    // 映射Java层的nativeGetByteArray方法到C++层的jniGetByteArray方法
    {"nativeGetByteArray", "(JLjava/lang/String;[B)[B", (void *) jniGetByteArray},
    // 映射Java层的nativeGetAll方法到C++层的jniGetAll方法
    {"nativeGetAll", "(J)Ljava/util/HashMap;", (void *) jniGetAll},
    // 映射Java层的nativeContainsKey方法到C++层的jniContainsKey方法
    {"nativeContainsKey", "(JLjava/lang/String;)Z", (void *) jniContainsKey},
    // 映射Java层的nativeReloadData方法到C++层的jniReloadData方法
    {"nativeReloadData", "(J)V", (void *) jniReloadData},
    // 其他方法映射...
};

3.2 基本类型读取实现

// Jni.cpp
// 读取布尔值
static jboolean jniGetBool(JNIEnv *env, jobject, jlong handle, jstring jkey, jboolean jdef) {
    // 将Java对象转换为C++对象
    MMKV *mmkv = (MMKV *) handle;
    if (!mmkv) {
        return jdef;
    }
    
    // 将Java字符串转换为C++字符串
    const char *key = env->GetStringUTFChars(jkey, nullptr);
    if (!key) {
        return jdef;
    }
    
    // 调用MMKV的getBool方法读取布尔值
    bool result = mmkv->getBool(key, (bool) jdef);
    
    // 释放Java字符串资源
    env->ReleaseStringUTFChars(jkey, key);
    
    return (jboolean) result;
}

// 读取int值
static jint jniGetInt(JNIEnv *env, jobject, jlong handle, jstring jkey, jint jdef) {
    MMKV *mmkv = (MMKV *) handle;
    if (!mmkv) {
        return jdef;
    }
    
    const char *key = env->GetStringUTFChars(jkey, nullptr);
    if (!key) {
        return jdef;
    }
    
    // 调用MMKV的getInt32方法读取int值
    int32_t result = mmkv->getInt32(key, (int32_t) jdef);
    
    env->ReleaseStringUTFChars(jkey, key);
    
    return (jint) result;
}

// 其他基本类型的读取方法实现类似...

3.3 复杂类型读取实现

// Jni.cpp
// 读取字符串
static jstring jniGetString(JNIEnv *env, jobject, jlong handle, jstring jkey, jstring jdef) {
    MMKV *mmkv = (MMKV *) handle;
    if (!mmkv) {
        return jdef;
    }
    
    const char *key = env->GetStringUTFChars(jkey, nullptr);
    if (!key) {
        return jdef;
    }
    
    // 调用MMKV的getString方法读取字符串
    string result = mmkv->getString(key, "");
    
    env->ReleaseStringUTFChars(jkey, key);
    
    if (result.empty()) {
        return jdef;
    }
    
    // 将C++字符串转换为Java字符串
    return env->NewStringUTF(result.c_str());
}

// 读取字节数组
static jbyteArray jniGetByteArray(JNIEnv *env, jobject, jlong handle, jstring jkey, jbyteArray jdef) {
    MMKV *mmkv = (MMKV *) handle;
    if (!mmkv) {
        return jdef;
    }
    
    const char *key = env->GetStringUTFChars(jkey, nullptr);
    if (!key) {
        return jdef;
    }
    
    // 调用MMKV的getByteArray方法读取字节数组
    MMBuffer result = mmkv->getByteArray(key, MMBuffer());
    
    env->ReleaseStringUTFChars(jkey, key);
    
    if (!result.length()) {
        return jdef;
    }
    
    // 创建Java字节数组并复制数据
    jbyteArray array = env->NewByteArray((jsize) result.length());
    if (array) {
        env->SetByteArrayRegion(array, 0, (jsize) result.length(), (const jbyte *) result.getPtr());
    }
    
    return array;
}

四、C++层数据读取核心

4.1 内存映射文件读取

// MMKV.cpp
// 从内存映射文件中读取数据
bool MMKV::getBool(const char *key, bool defaultValue) {
    // 加共享锁,允许多线程并发读取
    SCOPED_LOCK_SHARED;
    
    // 检查是否需要从文件重新加载数据
    if (m_needLoadFromFile) {
        loadFromFile();
        m_needLoadFromFile = false;
    }
    
    // 查找键对应的数据
    auto itr = m_dic.find(key);
    if (itr != m_dic.end()) {
        // 获取数据缓冲区
        MMBuffer &buffer = itr->second;
        if (buffer.length() >= Fixed32Size) {
            // 读取数据类型
            int32_t type = *(int32_t *) buffer.getPtr();
            if (type == TypeBool) {
                // 布尔值占4个字节,转换为bool类型
                return *(int32_t *) (buffer.getPtr() + Fixed32Size) != 0;
            }
        }
    }
    
    // 如果未找到或类型不匹配,返回默认值
    return defaultValue;
}

// 读取int32值
int32_t MMKV::getInt32(const char *key, int32_t defaultValue) {
    SCOPED_LOCK_SHARED;
    
    if (m_needLoadFromFile) {
        loadFromFile();
        m_needLoadFromFile = false;
    }
    
    auto itr = m_dic.find(key);
    if (itr != m_dic.end()) {
        MMBuffer &buffer = itr->second;
        if (buffer.length() >= Fixed32Size) {
            int32_t type = *(int32_t *) buffer.getPtr();
            if (type == TypeInt32) {
                // 读取int32值
                return *(int32_t *) (buffer.getPtr() + Fixed32Size);
            }
        }
    }
    
    return defaultValue;
}

// 其他基本类型的读取方法实现类似...

4.2 字符串读取

// MMKV.cpp
// 读取字符串
string MMKV::getString(const char *key, const string &defaultValue) {
    SCOPED_LOCK_SHARED;
    
    if (m_needLoadFromFile) {
        loadFromFile();
        m_needLoadFromFile = false;
    }
    
    auto itr = m_dic.find(key);
    if (itr != m_dic.end()) {
        MMBuffer &buffer = itr->second;
        if (buffer.length() > Fixed32Size) {
            int32_t type = *(int32_t *) buffer.getPtr();
            if (type == TypeString) {
                // 字符串长度(不包含类型标识的4个字节)
                size_t length = buffer.length() - Fixed32Size;
                // 复制字符串内容
                return string((const char *) buffer.getPtr() + Fixed32Size, length);
            }
        }
    }
    
    return defaultValue;
}

4.3 字节数组读取

// MMKV.cpp
// 读取字节数组
MMBuffer MMKV::getByteArray(const char *key, const MMBuffer &defaultValue) {
    SCOPED_LOCK_SHARED;
    
    if (m_needLoadFromFile) {
        loadFromFile();
        m_needLoadFromFile = false;
    }
    
    auto itr = m_dic.find(key);
    if (itr != m_dic.end()) {
        MMBuffer &buffer = itr->second;
        if (buffer.length() > Fixed32Size) {
            int32_t type = *(int32_t *) buffer.getPtr();
            if (type == TypeBytes) {
                // 复制字节数组内容(不包含类型标识的4个字节)
                size_t length = buffer.length() - Fixed32Size;
                return MMBuffer(buffer.getPtr() + Fixed32Size, length, MMBufferNoCopy);
            }
        }
    }
    
    return defaultValue;
}

4.4 复杂对象读取

// MMKV.cpp
// 读取自定义对象(示例)
bool MMKV::getCustomObject(const char *key, CustomObject &object) {
    SCOPED_LOCK_SHARED;
    
    if (m_needLoadFromFile) {
        loadFromFile();
        m_needLoadFromFile = false;
    }
    
    auto itr = m_dic.find(key);
    if (itr != m_dic.end()) {
        MMBuffer &buffer = itr->second;
        if (buffer.length() > Fixed32Size) {
            int32_t type = *(int32_t *) buffer.getPtr();
            if (type == TypeCustomObject) {
                // 跳过类型标识
                const uint8_t *ptr = buffer.getPtr() + Fixed32Size;
                size_t remaining = buffer.length() - Fixed32Size;
                
                // 从缓冲区解析对象
                CodedInputData input(ptr, remaining);
                
                // 读取对象的各个字段
                int32_t field1 = 0;
                string field2;
                vector<int32_t> field3;
                
                // 读取字段1
                if (!input.readInt32(field1)) {
                    return false;
                }
                
                // 读取字段2
                if (!input.readString(field2)) {
                    return false;
                }
                
                // 读取字段3
                size_t field3Size = 0;
                if (!input.readSize(field3Size)) {
                    return false;
                }
                field3.resize(field3Size);
                for (size_t i = 0; i < field3Size; i++) {
                    if (!input.readInt32(field3[i])) {
                        return false;
                    }
                }
                
                // 填充对象
                object.setField1(field1);
                object.setField2(field2);
                object.setField3(field3);
                
                return true;
            }
        }
    }
    
    return false;
}

五、数据解析与反序列化

5.1 数据格式概述

MMKV使用自定义的二进制格式存储数据,每个数据项包含:

  • 4字节类型标识
  • 数据内容

5.2 CodedInputData类

// CodedInputData.cpp
// 从缓冲区读取固定长度的int32值
bool CodedInputData::readInt32(int32_t &value) {
    if (m_position + Fixed32Size > m_size) {
        return false;
    }
    
    // 从当前位置读取int32值
    value = *(int32_t *) (m_ptr + m_position);
    m_position += Fixed32Size;
    
    return true;
}

// 从缓冲区读取字符串
bool CodedInputData::readString(string &value) {
    size_t size = 0;
    // 先读取字符串长度
    if (!readSize(size)) {
        return false;
    }
    
    if (m_position + size > m_size) {
        return false;
    }
    
    // 复制字符串内容
    value.assign((const char *) (m_ptr + m_position), size);
    m_position += size;
    
    return true;
}

// 从缓冲区读取变长大小值
bool CodedInputData::readSize(size_t &value) {
    if (m_position >= m_size) {
        return false;
    }
    
    // 读取一个字节
    uint8_t byte = m_ptr[m_position++];
    
    // 检查是否是单字节大小
    if (!(byte & 0x80)) {
        value = byte;
        return true;
    }
    
    // 多字节大小值
    uint64_t result = byte & 0x7F;
    int shift = 7;
    
    while (m_position < m_size) {
        byte = m_ptr[m_position++];
        result |= (uint64_t) (byte & 0x7F) << shift;
        shift += 7;
        
        if (!(byte & 0x80)) {
            value = (size_t) result;
            return true;
        }
    }
    
    // 数据不完整
    m_position = m_size;
    return false;
}

5.3 数据类型解析

// MMKV.cpp
// 从内存映射文件加载所有数据
bool MMKV::loadFromFile() {
    SCOPED_LOCK_EXCLUSIVE;
    
    // 检查文件是否存在
    if (!fileExists(m_path)) {
        // 文件不存在,创建空的内存映射
        m_actualSize = 0;
        m_dirty = true;
        return true;
    }
    
    // 读取文件内容
    int fd = open(m_path.c_str(), O_RDONLY, 0);
    if (fd < 0) {
        MMKVError("fail to open file %s: %s", m_path.c_str(), strerror(errno));
        return false;
    }
    
    // 获取文件大小
    struct stat st = {0};
    if (fstat(fd, &st) != 0) {
        close(fd);
        MMKVError("fail to fstat file %s: %s", m_path.c_str(), strerror(errno));
        return false;
    }
    
    size_t fileSize = (size_t) st.st_size;
    if (fileSize < Fixed32Size) {
        // 文件太小,不可能包含有效数据
        close(fd);
        return false;
    }
    
    // 映射文件到内存
    void *ptr = mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fd, 0);
    if (ptr == MAP_FAILED) {
        close(fd);
        MMKVError("fail to mmap file %s: %s", m_path.c_str(), strerror(errno));
        return false;
    }
    
    // 读取头部信息
    uint32_t header = *(uint32_t *) ptr;
    m_actualSize = header & 0x0FFFFFFF;
    
    if (m_actualSize + Fixed32Size > fileSize) {
        // 实际数据大小超过文件大小,数据损坏
        munmap(ptr, fileSize);
        close(fd);
        return false;
    }
    
    // 解析数据
    bool loaded = parseData((const uint8_t *) ptr + Fixed32Size, m_actualSize);
    
    // 解除内存映射
    munmap(ptr, fileSize);
    close(fd);
    
    return loaded;
}

// 解析数据内容
bool MMKV::parseData(const uint8_t *ptr, size_t length) {
    // 清空现有数据
    m_dic.clear();
    
    // 创建输入数据流
    CodedInputData input(ptr, length);
    
    // 解析所有键值对
    while (input.available()) {
        // 读取键
        string key;
        if (!input.readString(key)) {
            return false;
        }
        
        // 读取值类型
        int32_t type = 0;
        if (!input.readInt32(type)) {
            return false;
        }
        
        // 计算值的长度(剩余数据长度)
        size_t valueLength = input.available();
        
        // 根据类型解析值
        switch (type) {
            case TypeBool:
            case TypeInt32:
                // 基本类型,长度为4字节
                if (valueLength < Fixed32Size) {
                    return false;
                }
                valueLength = Fixed32Size;
                break;
                
            case TypeInt64:
            case TypeFloat:
            case TypeDouble:
                // 64位类型,长度为8字节
                if (valueLength < Fixed64Size) {
                    return false;
                }
                valueLength = Fixed64Size;
                break;
                
            case TypeString:
            case TypeBytes:
                // 字符串和字节数组,长度由数据决定
                size_t contentSize = 0;
                if (!CodedInputData::readRawVarint32(ptr + input.position(), contentSize)) {
                    return false;
                }
                valueLength = contentSize + CodedInputData::computeSizeOfSize(contentSize);
                if (valueLength > input.available()) {
                    return false;
                }
                break;
                
            default:
                // 未知类型,跳过
                MMKVWarning("unknown value type: %d", type);
                return false;
        }
        
        // 创建值缓冲区
        MMBuffer value(input.position(), valueLength, MMBufferNoCopy);
        
        // 将键值对添加到字典
        m_dic[key] = std::move(value);
        
        // 移动到下一个值
        input.forward(valueLength);
    }
    
    return true;
}

六、加密数据读取

6.1 加密机制概述

MMKV支持数据加密,加密后的数据在读取时需要先解密。

6.2 解密流程

// MMKV.cpp
// 读取加密的布尔值
bool MMKV::getEncryptedBool(const char *key, bool defaultValue) {
    SCOPED_LOCK_SHARED;
    
    if (m_needLoadFromFile) {
        loadFromFile();
        m_needLoadFromFile = false;
    }
    
    auto itr = m_dic.find(key);
    if (itr != m_dic.end()) {
        MMBuffer &buffer = itr->second;
        if (buffer.length() > Fixed32Size) {
            int32_t type = *(int32_t *) buffer.getPtr();
            if (type == TypeEncryptedBool) {
                // 创建解密后的缓冲区
                MMBuffer decrypted(buffer.length() - Fixed32Size);
                
                // 解密数据
                if (m_crypter) {
                    m_crypter->decrypt((unsigned char *) decrypted.getPtr(), 
                                      (unsigned char *) buffer.getPtr() + Fixed32Size, 
                                      decrypted.length());
                }
                
                // 解析解密后的数据
                if (decrypted.length() >= Fixed32Size) {
                    return *(int32_t *) decrypted.getPtr() != 0;
                }
            }
        }
    }
    
    return defaultValue;
}

// 读取加密的字符串
string MMKV::getEncryptedString(const char *key, const string &defaultValue) {
    SCOPED_LOCK_SHARED;
    
    if (m_needLoadFromFile) {
        loadFromFile();
        m_needLoadFromFile = false;
    }
    
    auto itr = m_dic.find(key);
    if (itr != m_dic.end()) {
        MMBuffer &buffer = itr->second;
        if (buffer.length() > Fixed32Size) {
            int32_t type = *(int32_t *) buffer.getPtr();
            if (type == TypeEncryptedString) {
                // 创建解密后的缓冲区
                MMBuffer decrypted(buffer.length() - Fixed32Size);
                
                // 解密数据
                if (m_crypter) {
                    m_crypter->decrypt((unsigned char *) decrypted.getPtr(), 
                                      (unsigned char *) buffer.getPtr() + Fixed32Size, 
                                      decrypted.length());
                }
                
                // 解析解密后的数据
                CodedInputData input((const uint8_t *) decrypted.getPtr(), decrypted.length());
                string result;
                if (input.readString(result)) {
                    return result;
                }
            }
        }
    }
    
    return defaultValue;
}

七、多进程数据读取

7.1 多进程同步机制

// MMKV.cpp
// 多进程模式下检查并加载最新数据
bool MMKV::checkLoadDataIfNeeded() {
    // 加进程间共享锁
    SCOPED_LOCK_SHARED_PROCESS;
    
    // 检查文件修改时间
    struct stat st = {0};
    if (stat(m_path.c_str(), &st) != 0) {
        return false;
    }
    
    // 比较当前文件修改时间与上次记录的时间
    if (st.st_mtime != m_lastModifiedTime || st.st_size != m_fileLength) {
        // 文件已修改,需要重新加载
        m_needLoadFromFile = true;
        m_lastModifiedTime = st.st_mtime;
        m_fileLength = st.st_size;
        return true;
    }
    
    return false;
}

// 多进程模式下读取布尔值
bool MMKV::getBoolMultiProcess(const char *key, bool defaultValue) {
    // 先检查是否需要加载最新数据
    if (checkLoadDataIfNeeded()) {
        // 加进程间排他锁,确保数据一致性
        SCOPED_LOCK_EXCLUSIVE_PROCESS;
        
        // 再次检查是否需要加载
        if (m_needLoadFromFile) {
            loadFromFile();
            m_needLoadFromFile = false;
        }
    }
    
    // 加共享锁,允许多线程并发读取
    SCOPED_LOCK_SHARED;
    
    // 从内存缓存读取数据
    auto itr = m_dic.find(key);
    if (itr != m_dic.end()) {
        MMBuffer &buffer = itr->second;
        if (buffer.length() >= Fixed32Size) {
            int32_t type = *(int32_t *) buffer.getPtr();
            if (type == TypeBool) {
                return *(int32_t *) (buffer.getPtr() + Fixed32Size) != 0;
            }
        }
    }
    
    return defaultValue;
}

7.2 文件锁机制

// FileLock.cpp
// 获取共享锁(读锁)
bool FileLock::lockShared() {
    struct flock lock = {};
    lock.l_type = F_RDLCK;  // 共享锁
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;  // 锁定整个文件
    
    // 调用fcntl系统调用获取锁
    return (fcntl(m_fd, F_SETLKW, &lock) == 0);
}

// 获取排他锁(写锁)
bool FileLock::lockExclusive() {
    struct flock lock = {};
    lock.l_type = F_WRLCK;  // 排他锁
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;  // 锁定整个文件
    
    // 调用fcntl系统调用获取锁
    return (fcntl(m_fd, F_SETLKW, &lock) == 0);
}

// 释放锁
bool FileLock::unlock() {
    struct flock lock = {};
    lock.l_type = F_UNLCK;  // 解锁
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;  // 解锁整个文件
    
    // 调用fcntl系统调用释放锁
    return (fcntl(m_fd, F_SETLK, &lock) == 0);
}

八、性能优化与缓存机制

8.1 内存缓存策略

// MMKV.cpp
// 获取所有键值对
unordered_map<string, MMBuffer> MMKV::getAll() {
    SCOPED_LOCK_SHARED;
    
    if (m_needLoadFromFile) {
        loadFromFile();
        m_needLoadFromFile = false;
    }
    
    // 返回内存缓存的副本
    return m_dic;
}

// 检查是否包含某个键
bool MMKV::containsKey(const char *key) {
    SCOPED_LOCK_SHARED;
    
    if (m_needLoadFromFile) {
        loadFromFile();
        m_needLoadFromFile = false;
    }
    
    // 检查内存缓存
    return m_dic.find(key) != m_dic.end();
}

8.2 最近最少使用(LRU)缓存

// LRUCache.h
template<typename K, typename V>
class LRUCache {
private:
    struct CacheEntry {
        K key;
        V value;
        
        CacheEntry(const K &k, const V &v) : key(k), value(v) {}
    };
    
    // 双向链表存储缓存项
    list<CacheEntry> m_cacheList;
    
    // 哈希表存储键到链表迭代器的映射
    unordered_map<K, typename list<CacheEntry>::iterator> m_cacheMap;
    
    // 缓存容量
    size_t m_capacity;
    
public:
    explicit LRUCache(size_t capacity) : m_capacity(capacity) {}
    
    // 获取缓存项
    bool get(const K &key, V &value) {
        auto itr = m_cacheMap.find(key);
        if (itr != m_cacheMap.end()) {
            // 找到缓存项,移到链表头部(最近使用)
            auto listItr = itr->second;
            CacheEntry entry = *listItr;
            
            // 从链表中删除
            m_cacheList.erase(listItr);
            
            // 插入到链表头部
            m_cacheList.push_front(entry);
            
            // 更新映射
            m_cacheMap[key] = m_cacheList.begin();
            
            // 返回值
            value = entry.value;
            return true;
        }
        
        return false;
    }
    
    // 添加缓存项
    void put(const K &key, const V &value) {
        auto itr = m_cacheMap.find(key);
        if (itr != m_cacheMap.end()) {
            // 已存在,删除旧项
            m_cacheList.erase(itr->second);
            m_cacheMap.erase(itr);
        }
        
        // 检查是否达到容量限制
        if (m_cacheMap.size() >= m_capacity) {
            // 移除最旧的项
            auto lastEntry = m_cacheList.back();
            m_cacheMap.erase(lastEntry.key);
            m_cacheList.pop_back();
        }
        
        // 添加新项到链表头部
        m_cacheList.push_front(CacheEntry(key, value));
        m_cacheMap[key] = m_cacheList.begin();
    }
    
    // 清空缓存
    void clear() {
        m_cacheList.clear();
        m_cacheMap.clear();
    }
};

// MMKV.cpp
// 使用LRU缓存优化读取性能
class MMKV {
private:
    // LRU缓存,用于优化读取性能
    LRUCache<string, MMBuffer> m_lruCache;
    
    // ...其他成员变量...
    
public:
    // 构造函数
    MMKV(const string &path, MMKVMode mode, const string &cryptKey)
        : m_path(path)
        , m_mode(mode)
        , m_lruCache(100)  // 缓存100个最近使用的项
        // ...其他初始化...
    {
        // ...构造函数其他代码...
    }
    
    // 优化的读取方法
    MMBuffer getOptimized(const char *key) {
        SCOPED_LOCK_SHARED;
        
        if (m_needLoadFromFile) {
            loadFromFile();
            m_needLoadFromFile = false;
        }
        
        // 先从LRU缓存中查找
        MMBuffer value;
        if (m_lruCache.get(key, value)) {
            return value;
        }
        
        // 从内存映射中查找
        auto itr = m_dic.find(key);
        if (itr != m_dic.end()) {
            // 添加到LRU缓存
            m_lruCache.put(key, itr->second);
            return itr->second;
        }
        
        return MMBuffer();
    }
};

九、常见问题与解决方案

9.1 数据读取失败

问题描述:调用MMKV读取数据返回默认值或失败。

可能原因

  1. 键名错误
  2. 数据类型不匹配
  3. 数据文件损坏
  4. 加密密钥不匹配

解决方案

  1. 检查键名是否正确
  2. 确保使用正确的数据类型读取方法
  3. 调用reload()方法重新加载数据
  4. 确保加密密钥一致

9.2 多进程数据不一致

问题描述:多进程环境下,不同进程读取到的数据不一致。

可能原因

  1. 文件修改未及时同步
  2. 锁机制使用不当
  3. 缓存未及时更新

解决方案

  1. 增加文件变化检测频率
  2. 确保正确使用多进程模式初始化MMKV
  3. 在适当的时候调用reload()方法刷新数据

9.3 读取性能问题

问题描述:大量数据读取时性能下降。

可能原因

  1. 频繁的文件IO
  2. 数据解析开销大
  3. 锁竞争激烈

解决方案

  1. 批量读取数据,减少IO次数
  2. 使用LRU缓存优化频繁访问的数据
  3. 考虑使用多线程并行读取