diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index 280d996698bdcecc875ee48bd8cf8e943af415b8..c83ae065a8ea6a6dd638ea02da3cc188155672d5 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -91,7 +91,8 @@ LATIN_IME_CORE_SRC_FILES := \
         byte_array_utils.cpp \
         dict_file_writing_utils.cpp \
         forgetting_curve_utils.cpp \
-        format_utils.cpp) \
+        format_utils.cpp \
+        mmapped_buffer.cpp) \
     suggest/policyimpl/gesture/gesture_suggest_policy_factory.cpp \
     $(addprefix suggest/policyimpl/typing/, \
         scoring_params.cpp \
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index f623b8d9d49adcd0676d5bf5ccf9e0ceb6c674f5..3becc7e39febf2c280f1133292cac1df0c2ac79e 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -86,11 +86,11 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jclass clazz, jstring s
     char sourceDirChars[sourceDirUtf8Length + 1];
     env->GetStringUTFRegion(sourceDir, 0, env->GetStringLength(sourceDir), sourceDirChars);
     sourceDirChars[sourceDirUtf8Length] = '\0';
-    DictionaryStructureWithBufferPolicy *const dictionaryStructureWithBufferPolicy =
+    DictionaryStructureWithBufferPolicy::StructurePoilcyPtr dictionaryStructureWithBufferPolicy(
             DictionaryStructureWithBufferPolicyFactory::newDictionaryStructureWithBufferPolicy(
                     sourceDirChars, static_cast<int>(dictOffset), static_cast<int>(dictSize),
-                    isUpdatable == JNI_TRUE);
-    if (!dictionaryStructureWithBufferPolicy) {
+                    isUpdatable == JNI_TRUE));
+    if (!dictionaryStructureWithBufferPolicy.get()) {
         return 0;
     }
 
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index 264b4605640c92c1359dff6d08dc17ae1409dd7d..7b83f27dfed7fadee9ef997f0e61322b8d80347e 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -21,9 +21,7 @@
 #include <stdint.h>
 
 #include "defines.h"
-#include "suggest/core/dictionary/bigram_dictionary.h"
 #include "suggest/core/policy/dictionary_header_structure_policy.h"
-#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
 #include "suggest/core/session/dic_traverse_session.h"
 #include "suggest/core/suggest.h"
 #include "suggest/core/suggest_options.h"
@@ -35,22 +33,15 @@ namespace latinime {
 
 const int Dictionary::HEADER_ATTRIBUTE_BUFFER_SIZE = 32;
 
-Dictionary::Dictionary(JNIEnv *env,
-        DictionaryStructureWithBufferPolicy *const dictionaryStructureWithBufferPolicy)
+Dictionary::Dictionary(JNIEnv *env, const DictionaryStructureWithBufferPolicy::StructurePoilcyPtr
+        &dictionaryStructureWithBufferPolicy)
         : mDictionaryStructureWithBufferPolicy(dictionaryStructureWithBufferPolicy),
-          mBigramDictionary(new BigramDictionary(mDictionaryStructureWithBufferPolicy)),
+          mBigramDictionary(new BigramDictionary(mDictionaryStructureWithBufferPolicy.get())),
           mGestureSuggest(new Suggest(GestureSuggestPolicyFactory::getGestureSuggestPolicy())),
           mTypingSuggest(new Suggest(TypingSuggestPolicyFactory::getTypingSuggestPolicy())) {
     logDictionaryInfo(env);
 }
 
-Dictionary::~Dictionary() {
-    delete mBigramDictionary;
-    delete mGestureSuggest;
-    delete mTypingSuggest;
-    delete mDictionaryStructureWithBufferPolicy;
-}
-
 int Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession,
         int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints,
         int inputSize, int *prevWordCodePoints, int prevWordLength, int commitPoint,
@@ -60,7 +51,7 @@ int Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession
     if (suggestOptions->isGesture()) {
         DicTraverseSession::initSessionInstance(
                 traverseSession, this, prevWordCodePoints, prevWordLength, suggestOptions);
-        result = mGestureSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates,
+        result = mGestureSuggest.get()->getSuggestions(proximityInfo, traverseSession, xcoordinates,
                 ycoordinates, times, pointerIds, inputCodePoints, inputSize, commitPoint, outWords,
                 frequencies, spaceIndices, outputTypes, outputAutoCommitFirstWordConfidence);
         if (DEBUG_DICT) {
@@ -70,7 +61,7 @@ int Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession
     } else {
         DicTraverseSession::initSessionInstance(
                 traverseSession, this, prevWordCodePoints, prevWordLength, suggestOptions);
-        result = mTypingSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates,
+        result = mTypingSuggest.get()->getSuggestions(proximityInfo, traverseSession, xcoordinates,
                 ycoordinates, times, pointerIds, inputCodePoints, inputSize, commitPoint,
                 outWords, frequencies, spaceIndices, outputTypes,
                 outputAutoCommitFirstWordConfidence);
@@ -84,7 +75,8 @@ int Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession
 int Dictionary::getBigrams(const int *word, int length, int *outWords, int *frequencies,
         int *outputTypes) const {
     if (length <= 0) return 0;
-    return mBigramDictionary->getPredictions(word, length, outWords, frequencies, outputTypes);
+    return mBigramDictionary.get()->getPredictions(word, length, outWords, frequencies,
+            outputTypes);
 }
 
 int Dictionary::getProbability(const int *word, int length) const {
@@ -98,39 +90,39 @@ int Dictionary::getProbability(const int *word, int length) const {
 
 int Dictionary::getBigramProbability(const int *word0, int length0, const int *word1,
         int length1) const {
-    return mBigramDictionary->getBigramProbability(word0, length0, word1, length1);
+    return mBigramDictionary.get()->getBigramProbability(word0, length0, word1, length1);
 }
 
 void Dictionary::addUnigramWord(const int *const word, const int length, const int probability) {
-    mDictionaryStructureWithBufferPolicy->addUnigramWord(word, length, probability);
+    mDictionaryStructureWithBufferPolicy.get()->addUnigramWord(word, length, probability);
 }
 
 void Dictionary::addBigramWords(const int *const word0, const int length0, const int *const word1,
         const int length1, const int probability) {
-    mDictionaryStructureWithBufferPolicy->addBigramWords(word0, length0, word1, length1,
+    mDictionaryStructureWithBufferPolicy.get()->addBigramWords(word0, length0, word1, length1,
             probability);
 }
 
 void Dictionary::removeBigramWords(const int *const word0, const int length0,
         const int *const word1, const int length1) {
-    mDictionaryStructureWithBufferPolicy->removeBigramWords(word0, length0, word1, length1);
+    mDictionaryStructureWithBufferPolicy.get()->removeBigramWords(word0, length0, word1, length1);
 }
 
 void Dictionary::flush(const char *const filePath) {
-    mDictionaryStructureWithBufferPolicy->flush(filePath);
+    mDictionaryStructureWithBufferPolicy.get()->flush(filePath);
 }
 
 void Dictionary::flushWithGC(const char *const filePath) {
-    mDictionaryStructureWithBufferPolicy->flushWithGC(filePath);
+    mDictionaryStructureWithBufferPolicy.get()->flushWithGC(filePath);
 }
 
 bool Dictionary::needsToRunGC(const bool mindsBlockByGC) {
-    return mDictionaryStructureWithBufferPolicy->needsToRunGC(mindsBlockByGC);
+    return mDictionaryStructureWithBufferPolicy.get()->needsToRunGC(mindsBlockByGC);
 }
 
 void Dictionary::getProperty(const char *const query, char *const outResult,
         const int maxResultLength) {
-    return mDictionaryStructureWithBufferPolicy->getProperty(query, outResult, maxResultLength);
+    return mDictionaryStructureWithBufferPolicy.get()->getProperty(query, outResult, maxResultLength);
 }
 
 void Dictionary::logDictionaryInfo(JNIEnv *const env) const {
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h
index 0195d5bf07d2162fdc74a27b82f14d8d9047c1be..e52a40f1d12ea271d29093bcd52b399898eec636 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary.h
@@ -21,14 +21,16 @@
 
 #include "defines.h"
 #include "jni.h"
+#include "suggest/core/dictionary/bigram_dictionary.h"
+#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
+#include "suggest/core/suggest_interface.h"
+#include "utils/exclusive_ownership_pointer.h"
 
 namespace latinime {
 
-class BigramDictionary;
 class DictionaryStructureWithBufferPolicy;
 class DicTraverseSession;
 class ProximityInfo;
-class SuggestInterface;
 class SuggestOptions;
 
 class Dictionary {
@@ -53,8 +55,8 @@ class Dictionary {
     static const int KIND_FLAG_POSSIBLY_OFFENSIVE = 0x80000000;
     static const int KIND_FLAG_EXACT_MATCH = 0x40000000;
 
-    Dictionary(JNIEnv *env,
-            DictionaryStructureWithBufferPolicy *const dictionaryStructureWithBufferPoilcy);
+    Dictionary(JNIEnv *env, const DictionaryStructureWithBufferPolicy::StructurePoilcyPtr
+            &dictionaryStructureWithBufferPoilcy);
 
     int getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession,
             int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints,
@@ -87,20 +89,22 @@ class Dictionary {
             const int maxResultLength);
 
     const DictionaryStructureWithBufferPolicy *getDictionaryStructurePolicy() const {
-        return mDictionaryStructureWithBufferPolicy;
+        return mDictionaryStructureWithBufferPolicy.get();
     }
 
-    virtual ~Dictionary();
-
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(Dictionary);
 
+    typedef ExclusiveOwnershipPointer<BigramDictionary> BigramDictionaryPtr;
+    typedef ExclusiveOwnershipPointer<SuggestInterface> SuggestInterfacePtr;
+
     static const int HEADER_ATTRIBUTE_BUFFER_SIZE;
 
-    DictionaryStructureWithBufferPolicy *const mDictionaryStructureWithBufferPolicy;
-    const BigramDictionary *const mBigramDictionary;
-    const SuggestInterface *const mGestureSuggest;
-    const SuggestInterface *const mTypingSuggest;
+    const DictionaryStructureWithBufferPolicy::StructurePoilcyPtr
+            mDictionaryStructureWithBufferPolicy;
+    const BigramDictionaryPtr mBigramDictionary;
+    const SuggestInterfacePtr mGestureSuggest;
+    const SuggestInterfacePtr mTypingSuggest;
 
     void logDictionaryInfo(JNIEnv *const env) const;
 };
diff --git a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
index 610de48ab4d92720060df19cd44d1c6d83a7c397..e649844dcaa49c06d1b220efaeee37d3a0655929 100644
--- a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
+++ b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
@@ -18,6 +18,7 @@
 #define LATINIME_DICTIONARY_STRUCTURE_POLICY_H
 
 #include "defines.h"
+#include "utils/exclusive_ownership_pointer.h"
 
 namespace latinime {
 
@@ -33,6 +34,8 @@ class DictionaryShortcutsStructurePolicy;
  */
 class DictionaryStructureWithBufferPolicy {
  public:
+    typedef ExclusiveOwnershipPointer<DictionaryStructureWithBufferPolicy> StructurePoilcyPtr;
+
     virtual ~DictionaryStructureWithBufferPolicy() {}
 
     virtual int getRootPosition() const = 0;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
index baa9cf142d235393a9429e063c967c414124151c..81783b53e524da5912a7524a8d475637de92e115 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
@@ -26,30 +26,32 @@
 
 namespace latinime {
 
-/* static */ DictionaryStructureWithBufferPolicy *DictionaryStructureWithBufferPolicyFactory
-        ::newDictionaryStructureWithBufferPolicy(const char *const path, const int bufOffset,
-                const int size, const bool isUpdatable) {
-    // Allocated buffer in MmapedBuffer::openBuffer() will be freed in the destructor of
-    // impl classes of DictionaryStructureWithBufferPolicy.
-    const MmappedBuffer *const mmapedBuffer = MmappedBuffer::openBuffer(path, bufOffset, size,
-            isUpdatable);
-    if (!mmapedBuffer) {
-        return 0;
+/* static */ DictionaryStructureWithBufferPolicy::StructurePoilcyPtr
+        DictionaryStructureWithBufferPolicyFactory
+                ::newDictionaryStructureWithBufferPolicy(const char *const path,
+                        const int bufOffset, const int size, const bool isUpdatable) {
+    // Allocated buffer in MmapedBuffer::newBuffer() will be freed in the destructor of
+    // MmappedBufferWrapper if the instance has the responsibility.
+    MmappedBuffer::MmappedBufferPtr mmappedBuffer(MmappedBuffer::openBuffer(path, bufOffset, size,
+            isUpdatable));
+    if (!mmappedBuffer.get()) {
+        return DictionaryStructureWithBufferPolicy::StructurePoilcyPtr(0);
     }
-    switch (FormatUtils::detectFormatVersion(mmapedBuffer->getBuffer(),
-            mmapedBuffer->getBufferSize())) {
+    switch (FormatUtils::detectFormatVersion(mmappedBuffer.get()->getBuffer(),
+            mmappedBuffer.get()->getBufferSize())) {
         case FormatUtils::VERSION_2:
-            return new PatriciaTriePolicy(mmapedBuffer);
+            return DictionaryStructureWithBufferPolicy::StructurePoilcyPtr(
+                    new PatriciaTriePolicy(mmappedBuffer));
         case FormatUtils::VERSION_3:
-            return new DynamicPatriciaTriePolicy(mmapedBuffer);
+            return DictionaryStructureWithBufferPolicy::StructurePoilcyPtr(
+                    new DynamicPatriciaTriePolicy(mmappedBuffer));
         case FormatUtils::VERSION_4:
             // TODO: Support version 4 dictionary format.
             // Fall through.
         default:
             AKLOGE("DICT: dictionary format is unknown, bad magic number");
-            delete mmapedBuffer;
             ASSERT(false);
-            return 0;
+            return DictionaryStructureWithBufferPolicy::StructurePoilcyPtr(0);
     }
 }
 
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h
index 8cebc3b1688e3b84a248530e6b2b3c35ecc25a75..1359575f1f6789face5aaf0fcd0c9cdc0c56656c 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h
@@ -21,13 +21,15 @@
 
 #include "defines.h"
 #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
+#include "utils/exclusive_ownership_pointer.h"
 
 namespace latinime {
 
 class DictionaryStructureWithBufferPolicyFactory {
  public:
-    static DictionaryStructureWithBufferPolicy *newDictionaryStructureWithBufferPolicy(
-            const char *const path, const int bufOffset, const int size, const bool isUpdatable);
+    static DictionaryStructureWithBufferPolicy::StructurePoilcyPtr
+            newDictionaryStructureWithBufferPolicy(const char *const path, const int bufOffset,
+                    const int size, const bool isUpdatable);
 
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(DictionaryStructureWithBufferPolicyFactory);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
index 31e6186b7b25e3a9e66e74872f53b7dad0c05b31..5d99632a5cc91dc493c3e0cc323a38768f2f5b69 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
@@ -34,16 +34,14 @@ class DicNodeVector;
 
 class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
  public:
-    PatriciaTriePolicy(const MmappedBuffer *const buffer)
-            : mBuffer(buffer), mHeaderPolicy(mBuffer->getBuffer(), FormatUtils::VERSION_2),
-              mDictRoot(mBuffer->getBuffer() + mHeaderPolicy.getSize()),
-              mDictBufferSize(mBuffer->getBufferSize() - mHeaderPolicy.getSize()),
+    PatriciaTriePolicy(const MmappedBuffer::MmappedBufferPtr &mmappedBuffer)
+            : mMmappedBuffer(mmappedBuffer),
+              mHeaderPolicy(mMmappedBuffer.get()->getBuffer(), FormatUtils::VERSION_2),
+              mDictRoot(mMmappedBuffer.get()->getBuffer() + mHeaderPolicy.getSize()),
+              mDictBufferSize(mMmappedBuffer.get()->getBufferSize()
+                      - mHeaderPolicy.getSize()),
               mBigramListPolicy(mDictRoot), mShortcutListPolicy(mDictRoot) {}
 
-    ~PatriciaTriePolicy() {
-        delete mBuffer;
-    }
-
     AK_FORCE_INLINE int getRootPosition() const {
         return 0;
     }
@@ -125,7 +123,7 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(PatriciaTriePolicy);
 
-    const MmappedBuffer *const mBuffer;
+    const MmappedBuffer::MmappedBufferPtr mMmappedBuffer;
     const HeaderPolicy mHeaderPolicy;
     const uint8_t *const mDictRoot;
     const int mDictBufferSize;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.cpp
index 246458d091e5b9dfaf7c7827ad72fe7afddf62ab..b9d4739da6f9206acedab48e92805c6943d086dc 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.cpp
@@ -216,7 +216,7 @@ int DynamicPatriciaTriePolicy::getBigramsPositionOfPtNode(const int ptNodePos) c
 
 bool DynamicPatriciaTriePolicy::addUnigramWord(const int *const word, const int length,
         const int probability) {
-    if (!mBuffer->isUpdatable()) {
+    if (!mMmappedBuffer.get()->isUpdatable()) {
         AKLOGI("Warning: addUnigramWord() is called for non-updatable dictionary.");
         return false;
     }
@@ -244,7 +244,7 @@ bool DynamicPatriciaTriePolicy::addUnigramWord(const int *const word, const int
 
 bool DynamicPatriciaTriePolicy::addBigramWords(const int *const word0, const int length0,
         const int *const word1, const int length1, const int probability) {
-    if (!mBuffer->isUpdatable()) {
+    if (!mMmappedBuffer.get()->isUpdatable()) {
         AKLOGI("Warning: addBigramWords() is called for non-updatable dictionary.");
         return false;
     }
@@ -278,7 +278,7 @@ bool DynamicPatriciaTriePolicy::addBigramWords(const int *const word0, const int
 
 bool DynamicPatriciaTriePolicy::removeBigramWords(const int *const word0, const int length0,
         const int *const word1, const int length1) {
-    if (!mBuffer->isUpdatable()) {
+    if (!mMmappedBuffer.get()->isUpdatable()) {
         AKLOGI("Warning: removeBigramWords() is called for non-updatable dictionary.");
         return false;
     }
@@ -308,7 +308,7 @@ bool DynamicPatriciaTriePolicy::removeBigramWords(const int *const word0, const
 }
 
 void DynamicPatriciaTriePolicy::flush(const char *const filePath) {
-    if (!mBuffer->isUpdatable()) {
+    if (!mMmappedBuffer.get()->isUpdatable()) {
         AKLOGI("Warning: flush() is called for non-updatable dictionary.");
         return;
     }
@@ -318,7 +318,7 @@ void DynamicPatriciaTriePolicy::flush(const char *const filePath) {
 }
 
 void DynamicPatriciaTriePolicy::flushWithGC(const char *const filePath) {
-    if (!mBuffer->isUpdatable()) {
+    if (!mMmappedBuffer.get()->isUpdatable()) {
         AKLOGI("Warning: flushWithGC() is called for non-updatable dictionary.");
         return;
     }
@@ -334,7 +334,7 @@ void DynamicPatriciaTriePolicy::flushWithGC(const char *const filePath) {
 }
 
 bool DynamicPatriciaTriePolicy::needsToRunGC(const bool mindsBlockByGC) const {
-    if (!mBuffer->isUpdatable()) {
+    if (!mMmappedBuffer.get()->isUpdatable()) {
         AKLOGI("Warning: needsToRunGC() is called for non-updatable dictionary.");
         return false;
     }
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.h
index 1a924c177dd62b50f9e4cf976fe2396942cdb50a..6a7f91ef6fbcbf270713610c909b9192ae24b5bb 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v3/dynamic_patricia_trie_policy.h
@@ -33,21 +33,20 @@ class DicNodeVector;
 
 class DynamicPatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
  public:
-    DynamicPatriciaTriePolicy(const MmappedBuffer *const buffer)
-            : mBuffer(buffer), mHeaderPolicy(mBuffer->getBuffer(), FormatUtils::VERSION_3),
-              mBufferWithExtendableBuffer(mBuffer->getBuffer() + mHeaderPolicy.getSize(),
-                      mBuffer->getBufferSize() - mHeaderPolicy.getSize(),
-                      BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE),
+    DynamicPatriciaTriePolicy(const MmappedBuffer::MmappedBufferPtr &mmappedBuffer)
+            : mMmappedBuffer(mmappedBuffer),
+              mHeaderPolicy(mMmappedBuffer.get()->getBuffer(), FormatUtils::VERSION_3),
+              mBufferWithExtendableBuffer(mMmappedBuffer.get()->getBuffer()
+                      + mHeaderPolicy.getSize(), mMmappedBuffer.get()->getBufferSize()
+                              - mHeaderPolicy.getSize(),
+                                      BufferWithExtendableBuffer
+                                              ::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE),
               mShortcutListPolicy(&mBufferWithExtendableBuffer),
               mBigramListPolicy(&mHeaderPolicy, &mBufferWithExtendableBuffer, &mShortcutListPolicy,
                       mHeaderPolicy.isDecayingDict()),
               mUnigramCount(mHeaderPolicy.getUnigramCount()),
               mBigramCount(mHeaderPolicy.getBigramCount()), mNeedsToDecayForTesting(false) {}
 
-    ~DynamicPatriciaTriePolicy() {
-        delete mBuffer;
-    }
-
     AK_FORCE_INLINE int getRootPosition() const {
         return 0;
     }
@@ -110,7 +109,7 @@ class DynamicPatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
     static const int MAX_DICT_EXTENDED_REGION_SIZE;
     static const int MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS;
 
-    const MmappedBuffer *const mBuffer;
+    const MmappedBuffer::MmappedBufferPtr mMmappedBuffer;
     const HeaderPolicy mHeaderPolicy;
     BufferWithExtendableBuffer mBufferWithExtendableBuffer;
     DynamicShortcutListPolicy mShortcutListPolicy;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..71f863290a51c6f73e8aca3788e7f0e0a342cddf
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h"
+
+#include <cerrno>
+#include <climits>
+#include <cstdio>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "suggest/policyimpl/dictionary/utils/file_utils.h"
+
+namespace latinime {
+
+/* static */ MmappedBuffer::MmappedBufferPtr MmappedBuffer::openBuffer(
+        const char *const path, const int bufferOffset, const int bufferSize,
+        const bool isUpdatable) {
+    const int openMode = isUpdatable ? O_RDWR : O_RDONLY;
+    const int mmapFd = open(path, openMode);
+    if (mmapFd < 0) {
+        AKLOGE("DICT: Can't open the source. path=%s errno=%d", path, errno);
+        return MmappedBufferPtr(0);
+    }
+    const int pagesize = getpagesize();
+    const int offset = bufferOffset % pagesize;
+    int alignedOffset = bufferOffset - offset;
+    int alignedSize = bufferSize + offset;
+    const int protMode = isUpdatable ? PROT_READ | PROT_WRITE : PROT_READ;
+    void *const mmappedBuffer = mmap(0, alignedSize, protMode, MAP_PRIVATE, mmapFd,
+            alignedOffset);
+    if (mmappedBuffer == MAP_FAILED) {
+        AKLOGE("DICT: Can't mmap dictionary. errno=%d", errno);
+        close(mmapFd);
+        return MmappedBufferPtr(0);
+    }
+    uint8_t *const buffer = static_cast<uint8_t *>(mmappedBuffer) + offset;
+    if (!buffer) {
+        AKLOGE("DICT: buffer is null");
+        close(mmapFd);
+        return MmappedBufferPtr(0);
+    }
+    return MmappedBufferPtr(new MmappedBuffer(buffer, bufferSize, mmappedBuffer, alignedSize,
+            mmapFd, isUpdatable));
+}
+
+/* static */ MmappedBuffer::MmappedBufferPtr MmappedBuffer::openBuffer(
+        const char *const path, const bool isUpdatable) {
+    const int fileSize = FileUtils::getFileSize(path);
+    if (fileSize == -1) {
+        return MmappedBufferPtr(0);
+    } else if (fileSize == 0) {
+        return MmappedBufferPtr(new MmappedBuffer(isUpdatable));
+    } else {
+        return openBuffer(path, 0 /* bufferOffset */, fileSize, isUpdatable);
+    }
+}
+
+/* static */ MmappedBuffer::MmappedBufferPtr MmappedBuffer::openBuffer(
+        const char *const dirPath, const char *const fileName, const bool isUpdatable) {
+    const int filePathBufferSize = PATH_MAX + 1 /* terminator */;
+    char filePath[filePathBufferSize];
+    const int filePathLength = snprintf(filePath, filePathBufferSize, "%s%s", dirPath,
+            fileName);
+    if (filePathLength >= filePathBufferSize) {
+        return 0;
+    }
+    return openBuffer(filePath, isUpdatable);
+}
+
+MmappedBuffer::~MmappedBuffer() {
+    if (mAlignedSize == 0) {
+        return;
+    }
+    int ret = munmap(mMmappedBuffer, mAlignedSize);
+    if (ret != 0) {
+        AKLOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno);
+    }
+    ret = close(mMmapFd);
+    if (ret != 0) {
+        AKLOGE("DICT: Failure in close. ret=%d errno=%d", ret, errno);
+    }
+}
+
+} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h
index 82138355dc974af45956eacea38922fb6f745ec5..73a733b0cf6e45098996d763946d2fb9e8f57622 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h
@@ -17,88 +17,27 @@
 #ifndef LATINIME_MMAPPED_BUFFER_H
 #define LATINIME_MMAPPED_BUFFER_H
 
-#include <cerrno>
-#include <climits>
-#include <cstdio>
-#include <fcntl.h>
 #include <stdint.h>
-#include <sys/mman.h>
-#include <unistd.h>
 
 #include "defines.h"
-#include "suggest/policyimpl/dictionary/utils/file_utils.h"
+#include "utils/exclusive_ownership_pointer.h"
 
 namespace latinime {
 
 class MmappedBuffer {
  public:
-    static MmappedBuffer *openBuffer(const char *const path, const int bufferOffset,
-            const int bufferSize, const bool isUpdatable) {
-        const int openMode = isUpdatable ? O_RDWR : O_RDONLY;
-        const int mmapFd = open(path, openMode);
-        if (mmapFd < 0) {
-            AKLOGE("DICT: Can't open the source. path=%s errno=%d", path, errno);
-            return 0;
-        }
-        const int pagesize = getpagesize();
-        const int offset = bufferOffset % pagesize;
-        int alignedOffset = bufferOffset - offset;
-        int alignedSize = bufferSize + offset;
-        const int protMode = isUpdatable ? PROT_READ | PROT_WRITE : PROT_READ;
-        void *const mmappedBuffer = mmap(0, alignedSize, protMode, MAP_PRIVATE, mmapFd,
-                alignedOffset);
-        if (mmappedBuffer == MAP_FAILED) {
-            AKLOGE("DICT: Can't mmap dictionary. errno=%d", errno);
-            close(mmapFd);
-            return 0;
-        }
-        uint8_t *const buffer = static_cast<uint8_t *>(mmappedBuffer) + offset;
-        if (!buffer) {
-            AKLOGE("DICT: buffer is null");
-            close(mmapFd);
-            return 0;
-        }
-        return new MmappedBuffer(buffer, bufferSize, mmappedBuffer, alignedSize, mmapFd,
-                isUpdatable);
-    }
+    typedef ExclusiveOwnershipPointer<MmappedBuffer> MmappedBufferPtr;
+
+    static MmappedBufferPtr openBuffer(const char *const path,
+            const int bufferOffset, const int bufferSize, const bool isUpdatable);
 
     // Mmap entire file.
-    static MmappedBuffer *openBuffer(const char *const path, const bool isUpdatable) {
-        const int fileSize = FileUtils::getFileSize(path);
-        if (fileSize == -1) {
-            return 0;
-        } else if (fileSize == 0) {
-            return new MmappedBuffer(isUpdatable);
-        } else {
-            return openBuffer(path, 0 /* bufferOffset */, fileSize, isUpdatable);
-        }
-    }
+    static MmappedBufferPtr openBuffer(const char *const path, const bool isUpdatable);
 
-    static MmappedBuffer *openBuffer(const char *const dirPath, const char *const fileName,
-            const bool isUpdatable) {
-        const int filePathBufferSize = PATH_MAX + 1 /* terminator */;
-        char filePath[filePathBufferSize];
-        const int filePathLength = snprintf(filePath, filePathBufferSize, "%s%s", dirPath,
-                fileName);
-        if (filePathLength >= filePathBufferSize) {
-            return 0;
-        }
-        return openBuffer(filePath, isUpdatable);
-    }
+    static MmappedBufferPtr openBuffer(const char *const dirPath, const char *const fileName,
+            const bool isUpdatable);
 
-    ~MmappedBuffer() {
-        if (mAlignedSize == 0) {
-            return;
-        }
-        int ret = munmap(mMmappedBuffer, mAlignedSize);
-        if (ret != 0) {
-            AKLOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno);
-        }
-        ret = close(mMmapFd);
-        if (ret != 0) {
-            AKLOGE("DICT: Failure in close. ret=%d errno=%d", ret, errno);
-        }
-    }
+    ~MmappedBuffer();
 
     AK_FORCE_INLINE uint8_t *getBuffer() const {
         return mBuffer;
diff --git a/native/jni/src/utils/exclusive_ownership_pointer.h b/native/jni/src/utils/exclusive_ownership_pointer.h
new file mode 100644
index 0000000000000000000000000000000000000000..3cf78954ade504d2246866f065c6739e5555ceca
--- /dev/null
+++ b/native/jni/src/utils/exclusive_ownership_pointer.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LATINIME_EXCLUSIVE_OWNERSHIP_POINTER_H
+#define LATINIME_EXCLUSIVE_OWNERSHIP_POINTER_H
+
+#include "defines.h"
+
+namespace latinime {
+
+template<class T>
+class ExclusiveOwnershipPointer {
+ public:
+    // This instance become an owner of the raw pointer.
+    ExclusiveOwnershipPointer(T *const rawPointer)
+            : mPointer(rawPointer),
+              mSharedOwnerPtr(new (ExclusiveOwnershipPointer<T> *)(this)) {}
+
+    // Move the ownership.
+    ExclusiveOwnershipPointer(const ExclusiveOwnershipPointer<T> &pointer)
+            : mPointer(pointer.mPointer), mSharedOwnerPtr(pointer.mSharedOwnerPtr) {
+        transferOwnership(&pointer);
+    }
+
+    ~ExclusiveOwnershipPointer() {
+        deletePointersIfHavingOwnership();
+    }
+
+    // Move the ownership.
+    ExclusiveOwnershipPointer<T> &operator=(const ExclusiveOwnershipPointer<T> &pointer) {
+        // Delete pointers when this is an owner of another pointer.
+        deletePointersIfHavingOwnership();
+        mPointer = pointer.mPointer;
+        mSharedOwnerPtr = pointer.mSharedOwnerPtr;
+        transferOwnership(pointer);
+        return *this;
+    }
+
+    T *get() const {
+        return mPointer;
+    }
+
+ private:
+    // This class allows to copy and assign and ensures only one instance has the ownership of the
+    // managed pointer.
+
+    ExclusiveOwnershipPointer() : mPointer(0), mSharedOwnerPtr(0) {}
+
+    void transferOwnership(const ExclusiveOwnershipPointer<T> *const src) {
+        if (*mSharedOwnerPtr != src) {
+           AKLOGE("Failed to transfer the ownership because src is not the current owner."
+                   "src: %p, owner: %p", src, *mSharedOwnerPtr);
+           ASSERT(false);
+           return;
+        }
+        // Transfer the ownership from src to this instance.
+        *mSharedOwnerPtr = this;
+    }
+
+    void deletePointersIfHavingOwnership() {
+        if (mSharedOwnerPtr && *mSharedOwnerPtr == this) {
+            if (mPointer) {
+                if (DEBUG_DICT) {
+                    AKLOGI("Releasing pointer: %p", mPointer);
+                }
+                delete mPointer;
+            }
+            delete mSharedOwnerPtr;
+        }
+    }
+
+    T *mPointer;
+    // mSharedOwnerPtr points a shared memory space where the instance which has the ownership is
+    // stored.
+    ExclusiveOwnershipPointer<T> **mSharedOwnerPtr;
+};
+} // namespace latinime
+#endif /* LATINIME_EXCLUSIVE_OWNERSHIP_POINTER_H */