IO优化是怎么做的,使用 SharedPreferences为什么这么卡,mmkv原理是什么

}

MMKV的使用非常简单, 所有变更立马生效,无需调用 sync、apply。 在 App 启动时初始化 MMKV,设定 MMKV 的根目录 (默认/data/data/xxx.xxx/files/mmkv/) (sp存储在/data/data/xxx.xxx/shared_prefs/)

支持从SP迁移数据importFromSharedPreferences

MMKV 还额外实现了一遍 SharedPreferences、SharedPreferences.Editor 这两个 interface

// 可以跟SP用法一样

SharedPreferences.Editor editor = mmkv.edit();

// 无需调用 commit()

//editor.commit();

MMKV 的使用非常简单,所有变更立马生效,无需调用 sync、apply。 在 App 启动时初始化 MMKV,设定 MMKV 的根目录(files/mmkv/),例如在 MainActivity 里:

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

String rootDir = MMKV.initialize(this);

System.out.println("mmkv root: " + rootDir);

//……

}

MMKV 提供一个全局的实例,可以直接使用:

import com.tencent.mmkv.MMKV;

//……

MMKV kv = MMKV.defaultMMKV();

kv.encode(“bool”, true);

boolean bValue = kv.decodeBool(“bool”);

kv.encode(“int”, Integer.MIN_VALUE);

int iValue = kv.decodeInt(“int”);

kv.encode(“string”, “Hello from mmkv”);

String str = kv.decodeString(“string”);

使用完毕的几个方法

public native void clearAll();

// MMKV’s size won’t reduce after deleting key-values

// call this method after lots of d

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

eleting f you care about disk usage

// note that clearAll has the similar effect of trim

public native void trim();

// call this method if the instance is no longer needed in the near future

// any subsequent call to the instance is undefined behavior

public native void close();

// call on memory warning

// any subsequent call to the instance will load all key-values from file again

public native void clearMemoryCache();

// you don’t need to call this, really, I mean it

// unless you care about out of battery

public void sync() {

sync(true);

}

1.5 补充适用建议

如果使用请务必做code19版本的适配,这个在github官网有说明

依赖下面这个库,然后对19区分处理

implementation ‘com.getkeepsafe.relinker:relinker:1.3.1’

if (android.os.Build.VERSION.SDK_INT == 19) {

MMKV.initialize(relativePath, new MMKV.LibLoader() {

@Override

public void loadLibrary(String libName) {

ReLinker.loadLibrary(context, libName);

}

});

} else {

MMKV.initialize(context);

}

1.6 限制

可看到,一个键会存入多分实例,最后存入的就是最新的。

MMKV 在大部分情况下都性能强劲,key/value 的数量和长度都没有限制。

然而 MMKV 在内存里缓存了所有的 key-value,在总大小比较大的情况下(例如 100M+),App 可能会爆内存,触发重整回写时,写入速度也会变慢。

支持大文件的 MMKV 正在开发中,有望在下一个大版本发布。

1.7 多进程使用

1.7.1锁 lock unlock tryLock

注意如果一个进程lock住,另一个进程mmkvWithID获取MMKV时就阻塞住,直到持有进程释放。

// get the lock immediately

MMKV mmkv2 = MMKV.mmkvWithID(LOCK_PHASE_2, MMKV.MULTI_PROCESS_MODE);

mmkv2.lock();

Log.d(“locked in child”, LOCK_PHASE_2);

Runnable waiter = new Runnable() {

@Override

public void run() {

//阻塞住 直到其他进程释放

MMKV mmkv1 = MMKV.mmkvWithID(LOCK_PHASE_1, MMKV.MULTI_PROCESS_MODE);

mmkv1.lock();

Log.d(“locked in child”, LOCK_PHASE_1);

}

};

​ 注意:如果其他进程有进行修改,不会立即触发onContentChangedByOuterProcess,

checkLoadData如果变化,会clearMemoryState,重新loadFromFile。//数据量大时不要太频繁

读取decodeXXX会阻塞住,先回调onContentChangedByOuterProcess,再返回值,保证值是最新的。

1.7.2 mmkvWithAshmemID 匿名共享内存

可以进行进程间通信,可设置pageSize

// a memory only MMKV, cleared on program exit

// size cannot change afterward (because ashmem won’t allow it)

1.7.3 测试结果

write速度: mmkv > cryptKV >> sp

read速度: sp > cryptKV > mmkv

1.8 Binder MMAP(一次拷贝)

​ Linux的内存分用户空间跟内核空间,同时页表有也分两类,用户空间页表跟内核空间页表,每个进程有一个用户空间页表,但是系统只有一个内核空间页表。

而Binder mmap的关键是:更新用户空间对应的页表的同时也同步映射内核页表,让两个页表都指向同一块地址,

​ 这样一来,数据只需要从A进程的用户空间,直接拷贝到B所对应的内核空间,而B多对应的内核空间在B进程的用户空间也有相应的映射,这样就无需从内核拷贝到用户空间了。

copy_from_user() //将数据从用户空间拷贝到内核空间

copy_to_user() //将数据从内核空间拷贝到用户空间

1.8.1 Liunx进程隔离

IO优化是怎么做的,使用 SharedPreferences为什么这么卡,mmkv原理是什么_第1张图片

1.8.2 传统IPC

IO优化是怎么做的,使用 SharedPreferences为什么这么卡,mmkv原理是什么_第2张图片

1.8.3 Binder通信

IO优化是怎么做的,使用 SharedPreferences为什么这么卡,mmkv原理是什么_第3张图片

1.9 普通文件mmap原理

普通文件的访问方式有两种

  1. ​ 第一种是通过read/write系统调访问,先在用户空间分配一段buffer,然后,进入内核,将内容从磁盘读 取到内核缓冲,最后,拷贝到用户进程空间,至少牵扯到两次数据拷贝;

同时,多个进程同时访问一个文件,每个进程都有一个副本,存在资源浪费的问题。

  1. ​ 另一种是通过mmap来访问文件,mmap()将文件直接映射到用户空间,文件在mmap的时候,内存并未 真正分配,

​ 只有在第一次读取/写入的时候才会触发,这个时候,会引发缺页中断,在处理缺页中断的时候,完成内存也分配,同时也完成文件数据的拷贝。

并且,修改用户空间对应的页表,完成到物理内存到用户空间的映射,这种方式只存在一次数据拷贝,效率更高。

同时多进程间通过mmap共享文件数据的时候,仅需要一块物理内存就够了。

​ Android中使用mmap,可以通过RandomAccessFile与MappedByteBuffer来配合。

通过randomAccessFile.getChannel().map获取到MappedByteBuffer。然后调用ByteBuffer的put方法添加数据。

RandomAccessFile randomAccessFile = new RandomAccessFile(“path”,“rw”);

你可能感兴趣的:(程序员,面试,移动开发,android)