標籤: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