android分析之Parcel

來源:互聯網
上載者:User

標籤:des   android   blog   io   os   使用   ar   java   strong   

將資料打包,跨進程傳輸(通過Binder)。看看這貨究竟是啥玩意:

Parcel.java :

public final class Parcel {    private static final boolean DEBUG_RECYCLE = false;    private static final String TAG = "Parcel";    @SuppressWarnings({"UnusedDeclaration"})    private int mNativePtr; // used by native code,非static     /**     * Flag indicating if {@link #mNativePtr} was allocated by this object,     * indicating that we‘re responsible for its lifecycle.     */    private boolean mOwnsNativeParcelObject;//非static,從上面解釋可以看到,它標識"mNativePtr”是否可用,如果是從NativeCode分配的,則要負責它的生命週期    private RuntimeException mStack;    private static final int POOL_SIZE = 6;    private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];//static,類擁有,下同。作為Parcel的緩衝池使用。    private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];

  下面看調用Parcel的obtain()時的過程:

    static protected final Parcel obtain() {        final Parcel[] pool = sHolderPool;//嘗試從sHolderPool這個緩衝池取        synchronized (pool) {            Parcel p;            for (int i=0; i<POOL_SIZE; i++) {//POOL_SIZE為6                p = pool[i];                if (p != null) {                    pool[i] = null;                    if (DEBUG_RECYCLE) {                        p.mStack = new RuntimeException();                    }                    p.init(obj);//找到一個可用的(非null),初始化這個Parcel                    return p;                }            }        }        return new Parcel(0);//如果6個都不可用(即緩衝池空了),則新new一個出來    }    private Parcel(int nativePtr) {        if (DEBUG_RECYCLE) {            mStack = new RuntimeException();        }        //Log.i(TAG, "Initializing obj=0x" + Integer.toHexString(obj), mStack);        init(nativePtr);//簡單調用    }    private void init(int nativePtr) {        if (nativePtr != 0) {            mNativePtr = nativePtr;            mOwnsNativeParcelObject = false;        } else {            mNativePtr = nativeCreate();//調用Native CODE            mOwnsNativeParcelObject = true;//表明,需要負責本Parcel對象的生命週期。後面有幾個方法會根據該boolean值決定是否釋放Native CODE產生的對象。        }    }

  小結:Parcel(.java)邏輯很簡單,從sHolderPool或者sOwnedPool中找不等於null的,取出來重新使用。否則,調用Native Code重建一個Parcel。在這裡,有mNativePtr和mOwnsNativeParcelObject兩個對象的成員變數,用來標識所產生的Native層的Parcel是否需要釋放/銷毀。

Parcel.h(.cpp)分析:

在Parcel.h中,存在許多欄位。實際上,可以將Parcel看作管理一塊記憶體的一個管理者。

    status_t            mError;    uint8_t*            mData;//指標,從字面上看應該是指向資料的指標    size_t              mDataSize;//表明資料大小,已經儲存的資料大小    size_t              mDataCapacity;//應該是記憶體空間的容量    mutable size_t      mDataPos;//mutable修飾,說明這個變數要及時反映出最新值,類比數組中position下標
size_t* mObjects;//指標,可以看作數組。其儲存的是每個儲存在Parcel對象所申請的記憶體的大小 size_t mObjectsSize;//與上面數組配合使用 size_t mObjectsCapacity; mutable size_t mNextObjectHint; mutable bool mFdsKnown; mutable bool mHasFds; bool mAllowFds; release_func mOwner; void* mOwnerCookie;

  從上面各個欄位來看,還是很經典的記憶體管理方式,這樣一般有:記憶體起始地址(對應上面mData)、記憶體總容量(對應mDataCapacity)、記憶體已用容量(對應mDataSize)、當前可用的記憶體位置(mDataPos)。在Parcel裡還更加細分了,每個儲存在記憶體中的對象大小。粒度更細。

Parcel::Parcel()//建構函式{    initState();}...void Parcel::initState()//簡單給各個成員變數賦初值{    mError = NO_ERROR;    mData = 0;    mDataSize = 0;    mDataCapacity = 0;    mDataPos = 0;    ALOGV("initState Setting data size of %p to %d\n", this, mDataSize);    ALOGV("initState Setting data pos of %p to %d\n", this, mDataPos);    mObjects = NULL;    mObjectsSize = 0;    mObjectsCapacity = 0;    mNextObjectHint = 0;    mHasFds = false;    mFdsKnown = true;    mAllowFds = true;    mOwner = NULL;}

  在setDataCapacity、setDataSize等函數中,調用到continueWrite,這個函數是真正的申請記憶體函數:

status_t Parcel::continueWrite(size_t desired){    // If shrinking, first adjust for any objects that appear    // after the new data size.    size_t objectsSize = mObjectsSize;    if (desired < mDataSize) {//表明需要縮小申請的記憶體容量        if (desired == 0) {            objectsSize = 0;        } else {            while (objectsSize > 0) {                if (mObjects[objectsSize-1] < desired)//找到一個對象的記憶體大小小於所要申請的記憶體大小                    break;                objectsSize--;            }        }    }        if (mOwner) {//mOwner是一個回呼函數指標        // If the size is going to zero, just release the owner‘s data.        if (desired == 0) {            freeData();//釋放資料            return NO_ERROR;        }        // If there is a different owner, we need to take        // posession.        uint8_t* data = (uint8_t*)malloc(desired);//分配記憶體        if (!data) {            mError = NO_MEMORY;            return NO_MEMORY;        }        size_t* objects = NULL;                if (objectsSize) {            objects = (size_t*)malloc(objectsSize*sizeof(size_t));//分配objectSize*sizeof(size_t)大小的記憶體            if (!objects) {                mError = NO_MEMORY;                return NO_MEMORY;            }            // Little hack to only acquire references on objects            // we will be keeping.            size_t oldObjectsSize = mObjectsSize;            mObjectsSize = objectsSize;            acquireObjects();//給各個對象增加強、弱引用計數——加入需要的話            mObjectsSize = oldObjectsSize;        }                if (mData) {            memcpy(data, mData, mDataSize < desired ? mDataSize : desired);//拷貝到data(新申請的)        }        if (objects && mObjects) {            memcpy(objects, mObjects, objectsSize*sizeof(size_t));        }        //ALOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());        mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);        mOwner = NULL;        mData = data;        mObjects = objects;        mDataSize = (mDataSize < desired) ? mDataSize : desired;        ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);        mDataCapacity = desired;        mObjectsSize = mObjectsCapacity = objectsSize;        mNextObjectHint = 0;    } else if (mData) {        if (objectsSize < mObjectsSize) {            // Need to release refs on any objects we are dropping.            const sp<ProcessState> proc(ProcessState::self());            for (size_t i=objectsSize; i<mObjectsSize; i++) {                const flat_binder_object* flat                    = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);                if (flat->type == BINDER_TYPE_FD) {                    // will need to rescan because we may have lopped off the only FDs                    mFdsKnown = false;                }                release_object(proc, *flat, this);//嘗試釋放對象            }            size_t* objects =                (size_t*)realloc(mObjects, objectsSize*sizeof(size_t));            if (objects) {                mObjects = objects;            }            mObjectsSize = objectsSize;            mNextObjectHint = 0;        }        // We own the data, so we can just do a realloc().        if (desired > mDataCapacity) {            uint8_t* data = (uint8_t*)realloc(mData, desired);//在原mData位置上重新分配記憶體            if (data) {                mData = data;                mDataCapacity = desired;            } else if (desired > mDataCapacity) {                mError = NO_MEMORY;                return NO_MEMORY;            }        } else {            if (mDataSize > desired) {                mDataSize = desired;                ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);            }            if (mDataPos > desired) {                mDataPos = desired;                ALOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);            }        }            } else {        // This is the first data.  Easy!        uint8_t* data = (uint8_t*)malloc(desired);//直接申請所需大小        if (!data) {            mError = NO_MEMORY;            return NO_MEMORY;        }                if(!(mDataCapacity == 0 && mObjects == NULL             && mObjectsCapacity == 0)) {            ALOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);        }                mData = data;        mDataSize = mDataPos = 0;        ALOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);        ALOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);        mDataCapacity = desired;    }    return NO_ERROR;}

  小結:上面記憶體配置管理比較細緻,總的來說就是“要麼新申請一塊記憶體”、“要麼複用一塊記憶體”,“釋放記憶體”,外加對象的生命週期的控制。

 

android分析之Parcel

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.