[Android]高性能MMKVデータインタラクティブ分析-MKV初期化
20772 ワード
皆さん、こんにちは、私は蒼王です.以下は私のこのシリーズの関連文章で、興味があれば参考にして、私の文章が好きか注目してもいいです.
[Android]どのようにして崩壊率が千分の3以下のアプリケーションapp-章のリストを作成します
組立体化群1はすでに満員で、入ってきたのは2 763094035を加えることができます
MMKVフレーム初期化
その後はjniの操作を呼び出しました
MMKV初期化、pthread_once()関数の詳細
マルチスレッド環境では、一度だけ実行する必要があることがあります.通常、アプリケーションを初期化する場合、main関数に簡単に配置できます.しかし、ライブラリを書くとmainで初期化できません.静的で初期化できますが、一度の初期化(pthread_once)を使うと簡単です.
int pthread_once(pthread_once_t *once_control, void (*init_routine) (void));
機能:この関数はPTHREAD_の初期値を使用します.ONCE_INITのonce_コントロール変数保証init_routine()関数は、このプロセス実行シーケンスで1回のみ実行されます.
マルチスレッドプログラミング環境ではpthread_once()呼び出しは複数のスレッドに表示され、init_routine()関数は1回のみ実行され,どのスレッドで実行されるかは不定であり,カーネルスケジューリングによって決定される.ではinitializeメソッドは1回しか実行されません.
保存されたフォルダを作成し、アドレス名を巡回してから、繰り返し作成します.
ファイル初期化の保存
MMKV初期化の作成
ファイルの読み込み
匿名メモリの読み込み
ストレージファイルの作成について説明します(ファイルと共有メモリに分かれます)
本節は第1編、第2~4編の分析ですが、すでに小欄に掲載されていますので、ご覧くださいhttps://xiaozhuanlan.com/cangwang_processより詳細な分析を表示します.
[Android]どのようにして崩壊率が千分の3以下のアプリケーションapp-章のリストを作成します
組立体化群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_コントロール変数保証init_routine()関数は、このプロセス実行シーケンスで1回のみ実行されます.
マルチスレッドプログラミング環境ではpthread_once()呼び出しは複数のスレッドに表示され、init_routine()関数は1回のみ実行され,どのスレッドで実行されるかは不定であり,カーネルスケジューリングによって決定される.ではinitializeメソッドは1回しか実行されません.
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;
}
}
}
本節は第1編、第2~4編の分析ですが、すでに小欄に掲載されていますので、ご覧くださいhttps://xiaozhuanlan.com/cangwang_processより詳細な分析を表示します.