CodeEggDailyInterview
CodeEggDailyInterview copied to clipboard
SharedPreferences 为什么存储大数据就比较占用内存?
SharedPreferencesImpl 会将 File 文件在子线程全部加载解析到一个内存的 Map 中,而 SharedPreferences 对象又会被 ContextImpl 的 static Map 进程 Cache 操作,所以 SharedPreferencesImpl 就相当于是一个单例存储的,故而其 Map 在内存中就会持续存在,即便使用 Editor 进行修改后 commit 操作实质也是对 SharedPreferencesImpl 中 Map 进行对应操作。
//一个SharedPreferences的get操作与Editor操作对应的内存Map操作原理
final class SharedPreferencesImpl implements SharedPreferences {
//用来存储该SP的所有Key-Value对
private Map<String, Object> mMap;
......
SharedPreferencesImpl(File file, int mode) {
......
//构造方法新起一个线程从磁盘加载SP文件解析XML到mMap中
startLoadFromDisk();
}
......
//通过SharedPreferences对象获取指定key的值
public int getInt(String key, int defValue) {
......
Integer v = (Integer)mMap.get(key);
return v != null ? v : defValue;
}
......
//通过SharedPreferences.edit()获取的Editor对象
public final class EditorImpl implements Editor {
//Editor要增删改查的操作Map记录
private final Map<String, Object> mModified = Maps.newHashMap();
......
public Editor putString(String key, @Nullable String value) {
......
mModified.put(key, value);
}
......
public Editor remove(String key) {
......
mModified.put(key, this);
}
......
//提交到内存mMap
// Returns true if any changes were made
private MemoryCommitResult commitToMemory() {
......
for (Map.Entry<String, Object> e : mModified.entrySet()) {
String k = e.getKey();
Object v = e.getValue();
if (v == this || v == null) {
if (!mMap.containsKey(k)) {
continue;
}
mMap.remove(k);
} else {
if (mMap.containsKey(k)) {
Object existingValue = mMap.get(k);
if (existingValue != null && existingValue.equals(v)) {
continue;
}
}
mMap.put(k, v);
}
changesMade = true;
if (hasListeners) {
keysModified.add(k);
}
}
//清空Editor的mModified的Map
mModified.clear();
......
}
......
//commit提交
public boolean commit() {
......
//提交到内存
MemoryCommitResult mcr = commitToMemory();
//提交到磁盘文件
SharedPreferencesImpl.this.enqueueDiskWrite(
mcr, null /* sync write on this thread okay */);
try {
mcr.writtenToDiskLatch.await();
} catch (InterruptedException e) {
return false;
} finally {
......
}
notifyListeners(mcr);
return mcr.writeToDiskResult;
}
......
}
}
可以理解成一个 SpFile 对应一个单例的 SharedPreferencesImpl 对象,这个单例的 SharedPreferencesImpl 实例化时会将文件全部加载到内存中以 Map 存储,然后 Editor 操作会 new 一个新的 modifyMap,接着到了 Editor 的 commit 操作时会将 modifyMap 进行遍历增删改查到 SharedPreferencesImpl 的 Map 中,然后进行存盘操作,而 SharedPreferencesImpl 进行 getX(key) 操作时都是直接从 SharedPreferencesImpl 的 Map 中进行读取的,所以说 SharedPreferences 只适合轻量级的数据存储操作。