日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android mmkv使用_[Android]高性能MMKV数据交互分析-MMKV初始化

發布時間:2023/12/20 Android 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android mmkv使用_[Android]高性能MMKV数据交互分析-MMKV初始化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

大家好,我系蒼王。

以下是我這個系列的相關文章,有興趣可以參考一下,可以給個喜歡或者關注我的文章。

Android組件化架構熱賣中

組件化群1已經滿員,進來的可以加群2 763094035

MMKV框架初始化

MMKV.initialize(this);

public static String initialize(Context context) {

//創建存儲目錄

rootDir = context.getFilesDir().getAbsolutePath() + "/mmkv";

initialize(rootDir);

return rootDir;

}

private static native void initialize(String var0);

之后是調用jni中的操作了

extern "C" JNIEXPORT JNICALL void

Java_com_tencent_mmkv_MMKV_initialize(JNIEnv *env, jobject obj, jstring rootDir) {

//c++中大于0和非空都是為真

if (!rootDir) {

return;

}

//string轉為char*

const char *kstr = env->GetStringUTFChars(rootDir, nullptr);

if (kstr) {

MMKV::initializeMMKV(kstr);

//初始化完后釋放kstr

env->ReleaseStringUTFChars(rootDir, kstr);

}

}

MMKV初始化,

pthread_once()函數詳解

在多線程環境中,有些事僅需要執行一次。通常當初始化應用程序時,可以比較容易地將其放在main函數中。但當你寫一個庫時,就不能在main里面初始化了,你可以用靜態初始化,但使用一次初始化(pthread_once)會比較容易些。

int pthread_once(pthread_once_t once_control, void (init_routine) (void));

功能:本函數使用初值為PTHREAD_ONCE_INIT的once_control變量保證init_routine()函數在本進程執行序列中僅執行一次。

在多線程編程環境下,盡管pthread_once()調用會出現在多個線程中,init_routine()函數僅執行一次,究竟在哪個線程中執行是不定的,是由內核調度來決定。

那么initialize方法只會執行一次。

void MMKV::initializeMMKV(const std::string &rootDir) {

//進程控制

static pthread_once_t once_control = PTHREAD_ONCE_INIT;

//進程中只執行一次initialize

pthread_once(&once_control, initialize);

//保存文件地址

g_rootDir = rootDir;

//strdup字符串拷貝

//c_str()函數返回一個指向正規C字符串的指針, 內容與本string串相同.這是為了與c語言兼容,在c語言中沒有string類型,故必須通過string類對象的成員函數c_str()把string 對象轉換成c中的字符串樣式。注意:一定要使用strcpy()函數 等來操作方法c_str()返回的指針

//需要分配空間的

char *path = strdup(g_rootDir.c_str());

//創建MmapedFile

mkPath(path);

//清除地址空間

free(path);

MMKVInfo("root dir: %s", g_rootDir.c_str());

}

void initialize() {

//建立哈希表

// 使用unordered_map優點因為內部實現了哈希表,因此其查找速度非常的快 ,缺點哈希表的建立比較耗費時間

g_instanceDic = new unordered_map<:string mmkv>;

//初始化線程鎖

g_instanceLock = ThreadLock();

//testAESCrypt();

MMKVInfo("page size:%d", DEFAULT_MMAP_SIZE);

}

//使用getpagesize函數獲得一頁內存大小

//系統給我們提供真正的內存時,用頁為單位提供,一次最少提供一頁的真實內存空間

//分配內存空間:你真實的分配了多少內存,就使用多少內存,不要越界使用

//但是系統提供的真實內存空間是以頁來提供的。

const int DEFAULT_MMAP_SIZE = getpagesize();

創建保存的文件夾,遍歷地址名,然后循環創建

bool mkPath(char *path) {

//文件(夾)信息結構體

struct stat sb = {};

bool done = false;

char *slash = path;

while (!done) {

//拿出文件夾名

slash += strspn(slash, "/");

slash += strcspn(slash, "/");

//遍歷到最尾部

done = (*slash == '\0');

*slash = '\0';

//如果文件夾不為空

if (stat(path, &sb) != 0) {

//創建文件夾

if (errno != ENOENT || mkdir(path, 0777) != 0) {

MMKVWarning("%s", path);

return false;

}

} else if (!S_ISDIR(sb.st_mode)) { //如果不是文件夾,拋錯誤

MMKVWarning("%s: %s", path, strerror(ENOTDIR));

return false;

}

*slash = '/';

}

return true;

}

保存文件初始化

//需要填寫mmapId,線程(單線程,多線程),加密密鑰

MMKV.mmkvWithID(mmapID, MMKV.SINGLE_PROCESS_MODE, cryptKey);

public static MMKV mmkvWithID(String mmapID, int mode, String cryptKey) {

if(rootDir == null) { //如果主目錄未初始化拋出異常

throw new IllegalStateException("You should Call MMKV.initialize() first.");

} else {

//id 不能超過46個字節

verifyMMID(mmapID);

創立出jni中分配的ID

long handle = getMMKVWithID(mmapID, mode, cryptKey);

return new MMKV(handle);

}

}

//mmkv的id是long類型

private static native long getMMKVWithID(String var0, int var1, String var2);

extern "C" JNIEXPORT JNICALL jlong Java_com_tencent_mmkv_MMKV_getMMKVWithID(

JNIEnv *env, jobject obj, jstring mmapID, jint mode, jstring cryptKey) {

MMKV *kv = nullptr; //初始化為空指針

if (!mmapID) { //如果為空,直接返回空指針

return (jlong) kv;

}

string str = jstring2string(env, mmapID); //格式化mmapId

if (cryptKey != nullptr) {

string crypt = jstring2string(env, cryptKey); //格式化密鑰

if (crypt.length() > 0) {

//創建文件,大小為一頁,和加密密鑰

kv = MMKV::mmkvWithID(str, DEFAULT_MMAP_SIZE, (MMKVMode) mode, &crypt);

}

}

if (!kv) { //如果創建失敗,重新創建一個不加密的文件

kv = MMKV::mmkvWithID(str, DEFAULT_MMAP_SIZE, (MMKVMode) mode, nullptr);

}

return (jlong) kv;

}

MMKV *MMKV::mmkvWithID(const std::string &mmapID, int size, MMKVMode mode, string *cryptKey) {

//如果mmapId為空范圍空指針

if (mmapID.empty()) {

return nullptr;

}

//設定單例鎖

SCOPEDLOCK(g_instanceLock);

//在記錄文件的map中找mampID,對應的mapFile文件

auto itr = g_instanceDic->find(mmapID);

//返回結束位置胡迭代器

//如果已經存在

if (itr != g_instanceDic->end()) {

//返回現在對應mmkv

MMKV *kv = itr->second;

return kv;

}

//新建一個mmkv

auto kv = new MMKV(mmapID, size, mode, cryptKey);

//保存到map中

(*g_instanceDic)[mmapID] = kv;

return kv;

}

創建MMKV 初始化

MMKV::MMKV(const std::string &mmapID, int size, MMKVMode mode, string *cryptKey)

: m_mmapID(mmapID)

, m_path(mappedKVPathWithID(m_mmapID, mode)) //構建mmkv文件地址

, m_crcPath(crcPathWithID(m_mmapID, mode)) //crc文件

, m_metaFile(m_crcPath, DEFAULT_MMAP_SIZE, (mode & MMKV_ASHMEM) ? MMAP_ASHMEM : MMAP_FILE) //初始化MmapedFile

, m_crypter(nullptr) //加密器

, m_fileLock(m_metaFile.getFd()) //文件鎖

, m_sharedProcessLock(&m_fileLock, SharedLockType) //進程鎖

, m_exclusiveProcessLock(&m_fileLock, ExclusiveLockType) //專用進程鎖

, m_isInterProcess((mode & MMKV_MULTI_PROCESS) != 0) //是否多進程

, m_isAshmem((mode & MMKV_ASHMEM) != 0) { //是否開啟共享內存

m_fd = -1;

m_ptr = nullptr;

m_size = 0;

m_actualSize = 0;

m_output = nullptr;

if (m_isAshmem) { //如果需要共享內存,需要使用創建共享共享內存的MmapedFile

m_ashmemFile = new MmapedFile(m_mmapID, static_cast(size), MMAP_ASHMEM);

//讀取匿名內存的文件fd地址

m_fd = m_ashmemFile->getFd();

} else {

m_ashmemFile = nullptr;

}

if (cryptKey && cryptKey->length() > 0) { //是否存在加密密鑰,存在則創建AES加密器

m_crypter = new AESCrypt((const unsigned char *) cryptKey->data(), cryptKey->length());

}

//是否直接沖文件加載

m_needLoadFromFile = true;

m_crcDigest = 0;

//是否開啟進程鎖

m_sharedProcessLock.m_enable = m_isInterProcess;

//是否開啟專用進程鎖

m_exclusiveProcessLock.m_enable = m_isInterProcess;

// sensitive zone

{

//單例鎖

SCOPEDLOCK(m_sharedProcessLock);

loadFromFile();

}

}

讀取文件

void MMKV::loadFromFile() {

if (m_isAshmem) { //是否使用匿名內存,是則初始化匿名內存

loadFromAshmem();

return;

}

m_metaInfo.read(m_metaFile.getMemory());

//打開文件,m_fd文件描述符

m_fd = open(m_path.c_str(), O_RDWR | O_CREAT, S_IRWXU);

if (m_fd < 0) { //文件不存在

MMKVError("fail to open:%s, %s", m_path.c_str(), strerror(errno));

} else {

m_size = 0;

struct stat st = {0};

if (fstat(m_fd, &st) != -1) { //文件狀態是否可讀

m_size = static_cast(st.st_size);

}

// round up to (n * pagesize)

if (m_size < DEFAULT_MMAP_SIZE || (m_size % DEFAULT_MMAP_SIZE != 0)) { //文件大小有內容,且小于1頁

size_t oldSize = m_size;

m_size = ((m_size / DEFAULT_MMAP_SIZE) + 1) * DEFAULT_MMAP_SIZE;

if (ftruncate(m_fd, m_size) != 0) { //指定文件大小輸出是否可行

MMKVError("fail to truncate [%s] to size %zu, %s", m_mmapID.c_str(), m_size,

strerror(errno));

m_size = static_cast(st.st_size);

}

zeroFillFile(m_fd, oldSize, m_size - oldSize); //清空文件

}

//將文件映射到內存

m_ptr = (char *) mmap(nullptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0);

//之后操作和匿名內存中操作相同

if (m_ptr == MAP_FAILED) {

MMKVError("fail to mmap [%s], %s", m_mmapID.c_str(), strerror(errno));

} else {

memcpy(&m_actualSize, m_ptr, Fixed32Size);

MMKVInfo("loading [%s] with %zu size in total, file size is %zu", m_mmapID.c_str(),

m_actualSize, m_size);

bool loaded = false;

if (m_actualSize > 0) {

if (m_actualSize < m_size && m_actualSize + Fixed32Size <= m_size) {

if (checkFileCRCValid()) {

MMKVInfo("loading [%s] with crc %u sequence %u", m_mmapID.c_str(),

m_metaInfo.m_crcDigest, m_metaInfo.m_sequence);

MMBuffer inputBuffer(m_ptr + Fixed32Size, m_actualSize, MMBufferNoCopy);

if (m_crypter) {

decryptBuffer(*m_crypter, inputBuffer);

}

//初始化Photobuf存儲結構orderedMap

m_dic = MiniPBCoder::decodeMap(inputBuffer);

m_output = new CodedOutputData(m_ptr + Fixed32Size + m_actualSize,

m_size - Fixed32Size - m_actualSize);

loaded = true;

}

}

}

if (!loaded) {

SCOPEDLOCK(m_exclusiveProcessLock);

if (m_actualSize > 0) {

writeAcutalSize(0);

}

m_output = new CodedOutputData(m_ptr + Fixed32Size, m_size - Fixed32Size);

recaculateCRCDigest();

}

MMKVInfo("loaded [%s] with %zu values", m_mmapID.c_str(), m_dic.size());

}

}

if (!isFileValid()) {

MMKVWarning("[%s] file not valid", m_mmapID.c_str());

}

m_needLoadFromFile = false;

}

讀取匿名內存

void MMKV::loadFromAshmem() {

//復制MmapedFile的段地址

m_metaInfo.read(m_metaFile.getMemory());

//如果匿名內存存在且匿名內存文件為真

if (m_fd < 0 || !m_ashmemFile) {

MMKVError("ashmem file invalid %s, fd:%d", m_path.c_str(), m_fd);

} else {

//讀取匿名內存文件大小

m_size = m_ashmemFile->getFileSize();

//讀取匿名內存起始地址

m_ptr = (char *) m_ashmemFile->getMemory();

if (m_ptr != MAP_FAILED) { //如果地址存在

//復制匿名內存出來

memcpy(&m_actualSize, m_ptr, Fixed32Size);

MMKVInfo("loading [%s] with %zu size in total, file size is %zu", m_mmapID.c_str(),

m_actualSize, m_size);

bool loaded = false;

if (m_actualSize > 0) {

if (m_actualSize < m_size && m_actualSize + Fixed32Size <= m_size) {

if (checkFileCRCValid()) {//檢查m_ptr和m_size都設置了

MMKVInfo("loading [%s] with crc %u sequence %u", m_mmapID.c_str(),

m_metaInfo.m_crcDigest, m_metaInfo.m_sequence);

//創造MMBuffer數據

MMBuffer inputBuffer(m_ptr + Fixed32Size, m_actualSize, MMBufferNoCopy);

if (m_crypter) { //如果加密,解密MMBuffer數據

decryptBuffer(*m_crypter, inputBuffer);

}

//

m_dic = MiniPBCoder::decodeMap(inputBuffer);

m_output = new CodedOutputData(m_ptr + Fixed32Size + m_actualSize,

m_size - Fixed32Size - m_actualSize);

//標志已經讀取成功

loaded = true;

}

}

}

if (!loaded) {

//使用范圍鎖

SCOPEDLOCK(m_exclusiveProcessLock);

if (m_actualSize > 0) {

writeAcutalSize(0);

}

//輸出流

m_output = new CodedOutputData(m_ptr + Fixed32Size, m_size - Fixed32Size);

//重新計算crc校驗

recaculateCRCDigest();

}

MMKVInfo("loaded [%s] with %zu values", m_mmapID.c_str(), m_dic.size());

}

}

if (!isFileValid()) {

MMKVWarning("[%s] ashmem not valid", m_mmapID.c_str());

}

m_needLoadFromFile = false;

}

說明一下存儲文件的創建(分為文件和共享內存)

MmapedFile::MmapedFile(const std::string &path, size_t size, bool fileType)

: m_name(path), m_fd(-1), m_segmentPtr(nullptr), m_segmentSize(0), m_fileType(fileType) {

if (m_fileType == MMAP_FILE) { //文件創建

//創建一個文件

m_fd = open(m_name.c_str(), O_RDWR | O_CREAT, S_IRWXU);

if (m_fd < 0) {

MMKVError("fail to open:%s, %s", m_name.c_str(), strerror(errno));

} else {

//文件屬性的訪問

struct stat st = {};

if (fstat(m_fd, &st) != -1) {

m_segmentSize = static_cast(st.st_size);

}

if (m_segmentSize < DEFAULT_MMAP_SIZE) {

m_segmentSize = static_cast(DEFAULT_MMAP_SIZE);

if (ftruncate(m_fd, m_segmentSize) != 0 || !zeroFillFile(m_fd, 0, m_segmentSize)) {

MMKVError("fail to truncate [%s] to size %zu, %s", m_name.c_str(),

m_segmentSize, strerror(errno));

close(m_fd);

m_fd = -1;

removeFile(m_name);

return;

}

}

m_segmentPtr =

(char *) mmap(nullptr, m_segmentSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0);

if (m_segmentPtr == MAP_FAILED) {

MMKVError("fail to mmap [%s], %s", m_name.c_str(), strerror(errno));

close(m_fd);

m_fd = -1;

m_segmentPtr = nullptr;

}

}

} else {

//共享內存創建 #define ASHMEM_NAME_DEF "/dev/ashmem"

m_fd = open(ASHMEM_NAME_DEF, O_RDWR);

if (m_fd < 0) { //創建失敗

MMKVError("fail to open ashmem:%s, %s", m_name.c_str(), strerror(errno));

} else {

if (ioctl(m_fd, ASHMEM_SET_NAME, m_name.c_str()) != 0) { //內存訪問io控制

MMKVError("fail to set ashmem name:%s, %s", m_name.c_str(), strerror(errno));

} else if (ioctl(m_fd, ASHMEM_SET_SIZE, size) != 0) {

MMKVError("fail to set ashmem:%s, size %d, %s", m_name.c_str(), size,

strerror(errno));

} else { //訪問成功

//獲取頁長度

m_segmentSize = static_cast(size);

//獲取頁指針

m_segmentPtr = (char *) mmap(nullptr, m_segmentSize, PROT_READ | PROT_WRITE,

MAP_SHARED, m_fd, 0);

if (m_segmentPtr == MAP_FAILED) {

MMKVError("fail to mmap [%s], %s", m_name.c_str(), strerror(errno));

m_segmentPtr = nullptr;

} else {

return;

}

}

close(m_fd);

m_fd = -1;

}

}

}

MMKV初始化內容

總結

以上是生活随笔為你收集整理的android mmkv使用_[Android]高性能MMKV数据交互分析-MMKV初始化的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。