ListView回收机制相关分析
最初的分析文档为word,该文档是直接从word文档发布,布局未做详细调整,凑合看吧。
所用源码版本为最新的Android 4.4.2(API 19)。更新中……
ListView结构关系
首先理清listview的层级关系,
使用Google Online Draw 画出继承关系图如下:
图中单独画出Scrollview是为了说明该ViewGroup并没有自带回收机制,如果要是Scrollview显示大量view,需要手动做处理。
重要的类有三个:Listview、AbsListView、AdapterView。各个类的大小如下:
- Listview 3800
- AbsListView 6920
- AdapterView 1208
从Listview开始, ListView的初始化ListVIew.onLayout过程与普通视图的layout过程不同,流程图如下。从左向右,从上向下。
视图的创建过程的都会执行的三个步骤: onMeasure, onLayout, onDraw
图中可以看出重要的类有三个:Listview、AbsListView、AdapterView。主要的回收类RecycleBin位于AbsListView中。
RecycleBin类解析
位于AbsListView中,6466-6900行。
AbsListView的源码中可以看到有个RecycleBin 对象mRecycler。(317行, The data set used to store unused views that should be reused during the next layout to avoid creating new ones. 用于存储不用的view,以便在下个layout中使用来避免创建新的。)注释说明:
The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the start of a layout. By construction, they are displaying current information. At the end of layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that could potentially be used by the adapter to avoid allocating views unnecessarily.
大意是使用两级view来进行回收:
ActiveView
:激活view,当期显示在屏幕上的激活的view。
ScrapView
:废弃view,被删除的ActiveView会被自动加入ScrapView。
然后看看RecycleBin内部的重要的的变量和方法:
2.1 RecycleBin变量
mRecyclerListener
: 当发生View回收时,mRecyclerListener若有注册,则会通知给注册者.RecyclerListener接口只有一个函数onMovedToScrapHeap,指明某个view被回收到了scrap heap. 该view不再被显示,任何相关的昂贵资源应该被丢弃。该函数是处理回收时view中的资源释放。
mFirstActivePosition
:The position of the first view stored in mActiveViews.存储在mActiveViews中的第一个view的位置,即getFirstVisiblePosition。
mActiveViews
: Views that were on screen at the start of layout. This array is populated at the start of layout, and at the end of layout all view in mActiveViews are moved to mScrapViews. Views in mActiveViews represent a contiguous range of Views, with position of the first view store in mFirstActivePosition.布局开始时屏幕显示的view,这个数组会在布局开始时填充,布局结束后所有view被移至mScrapViews。
mScrapViews
:ArrayList<View>[] Unsorted views that can be used by the adapter as a convert view.可以被适配器用作convert view的无序view数组。 这个ArrayList就是adapter中getView方法中的参数convertView的来源。注意:这里是一个数组,因为如果adapter中数据有多种类型,那么就会有多个ScrapViews。
mViewTypeCount
:view类型总数,列表中可能有多种数据类型,比如内容数据和分割符。
mCurrentScrap
:跟mScrapViews的却别是,mScrapViews是个队列数组,ArrayList<View>[]类型,数组长度为mViewTypeCount,而默认ViewTypeCount = 1的情况下mCurrentScrap=mScrapViews[0]。
下面三个参数分别对应addScrapView中scrapHasTransientState的三个情况
- mTransientStateViews: If the data hasn't changed, we can reuse the views at their old positions.
- mTransientStateViewsById: If the adapter has stable IDs,we can reuse the view forthe same data.
- mSkippedScrap:Otherwise, we'll have to remove the view and start over.
2.2 RecycleBin方法
markChildrenDirty
():为每个子类调用forceLayout()。将mScrapView中回收回来的View设置一样标志,在下次被复用到ListView中时,告诉viewroot重新layout该view。forceLayout()方法只是设置标志,并不会通知其parent来重新layout。
shouldRecycleViewType
():判断给定的view的viewType指明是否可以回收回。viewType < 0可以回收。指定忽略的( ITEM_VIEW_TYPE_IGNORE = -1),或者是 HeaderView / (FootViewITEM_VIEW_TYPE_HEADER_OR_FOOTER = -2)是不被回收的。如有特殊需要可以将自己定义的viewType设置为-1,否则,将会浪费内存,导致OOM。
clear
() :Clears the scrap heap.清空废弃view堆,并将这些View从窗口中Detach。
fillActiveViews
(int childCount, int firstActivePosition):Fill ActiveViews with all of the children of the AbsListView. childCount:The minimum number of views mActiveViews should hold. firstActivePosition:The position of the first view that will be stored in mActiveViews.用AbsListView.的所有子view填充ActiveViews,其中childCount是mActiveViews应该保存的最少的view数,firstActivePosition是mActiveViews中存储的首个view的位置。从代码看该方法的处理逻辑为将当前AbsListView的0-childCount个子类中的非header、footer类添加到mActiveViews数组中。当Adapter中的数据个数未发生变化时,此时用户可能只是滚动,或点击等操作,ListView中item的个数会发生变化,因此,需要将可视的item加入到mActiveView中来管理。
getActiveView
(int position):Get the view corresponding to the specified position. The view will be removed from mActiveViews if it is found. 获取mActiveViews中指定位置的view,如果找到会将该view从mActiveViews中移除。position是adapter中的绝对下标值,mFirstActivePosition前面说过了,是当前可视区域的下标值,对应在adapter中的绝对值,如果找到,则返回找到的View,并将mActiveView对应的位置设置为null。
clearTransientStateViews()
:Dump any currently saved views with transient state.清掉当前处于transient(转换)状态的所有保存的view。内部为mTransientStateViews和mTransientStateViewsById的clear()调用。
addScrapView
(View scrap, int position):将view放入scrapview list中。If the list data hasn't changed or the adapter has stable IDs, views with transient state will be preserved for later retrieval. scrap:要添加的view。Position:view在父类中的位置。放入时位置赋给scrappedFromPosition 。有transient状态的view不会被scrap(废弃),会被加入mSkippedScrap。
就是将移出可视区域的view,设置它的scrappedFromPosition,然后从窗口中detach该view,并根据viewType加入到mScrapView中。
该方法会调用mRecyclerListener 接口的函数onMovedToScrapHeap(6734)
if (mRecyclerListener != null) { mRecyclerListener.onMovedToScrapHeap(scrap); } |
mRecyclerListener的设置可通过AbsListView的setRecyclerListener方法。
当view被回收准备再利用的时候设置要通知的监听器, 可以用来释放跟view有关的资源。这点似乎很有用。
public void setRecyclerListener(RecyclerListener listener) { mRecycler.mRecyclerListener = listener; } |
getScrapView
(int position) :A view from the ScrapViews collection. These are unordered.该方法中调用了retrieveFromScrap(ArrayList<View> scrapViews, int position)。
retrieveFromScrap
(ArrayList<View> scrapViews, int position):无注释。(6902)该方法属于AbsListView。
int size = scrapViews.size(); if (size > 0) { // See if we still have a view for this position. for (int i=0; i<size; i++) { View view = scrapViews.get(i); if (((AbsListView.LayoutParams)view.getLayoutParams()) .scrappedFromPosition == position) { scrapViews.remove(i); return view; } } return scrapViews.remove(size - 1); } else { return null; } |
其中scrappedFromPosition :The position the view was removed from when pulled out of the scrap heap.(6412)根据position,从mScrapView中找:
1. 如果有view.scrappedFromPosition = position的,直接返回该view;
2. 否则返回mScrapView中最后一个;
3. 如果缓存中没有view,则返回null;
a. 第三种情况,这个最简单:
一开始,listview稳定后,显示N个,此时mScrapView中是没有缓存view的,当我们向上滚动一小段距离(第一个此时仍显示部分),新的view将会显示,此时listview会调用Adapter.getView,但是缓存中没有,因此convertView是null,所以,我们得分配一块内存来创建新的convertView;
b. 第二种情况:
在a中,我们继续向上滚动,直接第一个view完全移出屏幕(假设没有新的item),此时,第一个view就会被detach,并被加入到mScrapView中;然后,我们还继续向上滚动,直接后面又将要显示新的item view时,此时,系统会从mScrapView中找position对应的View,显然,是找不到的,则将从mScrapView中,取最后一个缓存的view传递给convertView;
c. 第一种情况:
紧接着在b中,第一个被完全移出,加入到mScrapView中,且没有新增的item到listview中,此时,缓存中就只有第一个view;然后,我此时向下滑动,则之前的第一个item,将被显示出来,此时,从缓存中查找position对应的view有没有,当然,肯定是找到了,就直接返回了。
removeSkippedScrap()
:Finish the removal of any views that skipped the scrap heap.清空mSkippedScrap。
scrapActiveViews
():Move all views remaining in mActiveViews to mScrapViews.将mActiveViews 中剩余的view放入mScrapViews。实际上就是将mActiveView中未使用的view回收(因为,此时已经移出可视区域了)。会调用mRecyclerListener.onMovedToScrapHeap(scrap);
pruneScrapViews
():确保mScrapViews 的数目不会超过mActiveViews的数目 (This can happen if an adapter does not recycle its views)。mScrapView中每个ScrapView数组大小不应该超过mActiveView的大小,如果超过,系统认为程序并没有复用convertView,而是每次都是创建一个新的view,为了避免产生大量的闲置内存且增加OOM的风险,系统会在每次回收后,去检查一下,将超过的部分释放掉,节约内存降低OOM风险。
reclaimScrapViews
(List<View> views):Puts all views in the scrap heap into the supplied list.将mScrapView中所有的缓存view全部添加到指定的view list中,只看到有AbsListView.reclaimViews有调用到,但没有其它方法使用这个函数,可能在特殊情况下会使用到,但目前从framework中,看不出来。
setCacheColorHint
(int color):Updates the cache color hint of all known views.更新view的缓存颜色提示setDrawingCacheBackgroundColor。为所有的view绘置它们的背景色。
RecycleBin的调用和关键方法
3.1 ListView
3.1.1 layoutChildren
1479-1729
1583-当数据发生改变的时候,把当前的view放到scrapviews里面,否则标记为activeViews。
// Pull all children into the RecycleBin. // These views will be reused if possible final int firstPosition = mFirstPosition; final RecycleBin recycleBin = mRecycler; if (dataChanged) { for (int i = 0; i < childCount; i++) { recycleBin.addScrapView(getChildAt(i), firstPosition+i); } }else { recycleBin.fillActiveViews(childCount, firstPosition); } // Clear out old views detachAllViewsFromParent(); recycleBin.removeSkippedScrap();//移除所有old views ...... // Flush any cached views that did not get reused above recycleBin.scrapActiveViews();//刷新缓存,将当前的ActiveVies 移动到 ScrapViews。 |
dataChanged,从单词的意思我们就可以,这里的优化规则就是基于数据是否有变化,mDataChanged在makeAndAddView(见下文)中有使用。
step1:如果数据发生变化,就将所有view加入到mScrapView中,否则,将所有view放到mActiveView中;
step2:添加view到listview中;
step3:回收mActiveView中的未使用的view到mScrapView中;
注:在step1中,如果是addScrapView,则所有的view将会detach,如果是fillActiveViews,则不会detach,只有在step3中,未用到的view才会detach。
3.1.2 makeAndAddView
(int position, int y, boolean flow, int childrenLeft,boolean selected)(1772)
Obtain the view and add it to our list of children. The view can be made fresh, converted from an unused view, or used as is if it was in the recycle bin.
View child; if (!mDataChanged) {// 数据没有更新时,使用以前的view // Try to use an existing view for this position child = mRecycler.getActiveView(position); if (child != null) { // Found it -- we're using an existing child // This just needs to be positioned // 对复用的View针对当前需要进行配置。定位并且添加这个view到ViewGrop中的children列表,从回收站获取的视图不需要measure,所以最后一个参数为true setupChild(child, position, y, flow, childrenLeft, selected, true); return child; } } // Make a new view for this position, or convert an unused view if possible // 创建或者重用视图 child = obtainView(position, mIsScrap); // This needs to be positioned and measured setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]); return child; |
3.1.3 setupChild
(View child, int position, int y, boolean flowDown, int childrenLeft, boolean selected, boolean recycled)(1812)
Add a view as a child and make sure it is measured (if necessary) and positioned properly.
3.1.4 setAdapter
(ListAdapter adapter) (457)
Sets the data behind this ListView. The adapter passed to this method may be wrapped by a WrapperListAdapter, depending on the ListView features currently in use. For instance, adding headers and/or footers will cause the adapter to be wrapped.
if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver);//移除了与当前listview的adapter绑定数据集观察者DataSetObserver } resetList();//重置listview,主要是清除所有的view,改变header、footer的状态 mRecycler.clear();//清除掉RecycleBin对象mRecycler中所有缓存的view,RecycleBin后面着重介绍,主要是关系到Listview中item的重用机制,它是AbsListview的一个内部类 if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {//判断是否有headerview和footview mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; } mOldSelectedPosition = INVALID_POSITION; mOldSelectedRowId = INVALID_ROW_ID; // AbsListView#setAdapter will update choice mode states. super.setAdapter(adapter); if (mAdapter != null) { mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); mOldItemCount = mItemCount; mItemCount = mAdapter.getCount(); checkFocus(); mDataSetObserver = new AdapterDataSetObserver();//注册headerview的观察者 mAdapter.registerDataSetObserver(mDataSetObserver);//在RecycleBin对象mRecycler记录下item类型的数量 mRecycler.setViewTypeCount(mAdapter.getViewTypeCount()); int position; if (mStackFromBottom) { position = lookForSelectablePosition(mItemCount - 1, false); } else { position = lookForSelectablePosition(0, true); } setSelectedPositionInt(position);//AdapterView中的方法,记录当前的position setNextSelectedPositionInt(position);//AdapterView中的方法,记录下一个position if (mItemCount == 0) { // Nothing selected checkSelectionChanged(); } } else { mAreAllItemsSelectable = true; checkFocus(); // Nothing selected checkSelectionChanged(); } requestLayout(); |
3.1.5 scrollListItemsBy
(int amount)(3012-3082)
对子view滑动一定距离,添加view到底部或者移除顶部的不可见view。从注释看,不可见的item 的自动移除是在scrollListItemsBy中进行的。
private void scrollListItemsBy(int amount) { offsetChildrenTopAndBottom(amount); final int listBottom = getHeight() - mListPadding.bottom;//获取listview最底部位置 final int listTop = mListPadding.top; //获取listview最顶部位置 final AbsListView.RecycleBin recycleBin = mRecycler; if (amount < 0) { // shifted items up // may need to pan views into the bottom space int numChildren = getChildCount(); View last = getChildAt(numChildren - 1); while (last.getBottom() < listBottom) {//最后的view高于底部时添加下一个view final int lastVisiblePosition = mFirstPosition + numChildren - 1; if (lastVisiblePosition < mItemCount - 1) { last = addViewBelow(last, lastVisiblePosition); numChildren++; } else { break; } } // may have brought in the last child of the list that is skinnier // than the fading edge, thereby leaving space at the end. need // to shift back if (last.getBottom() < listBottom) {//到达最后一个view offsetChildrenTopAndBottom(listBottom - last.getBottom()); } // top views may be panned off screen View first = getChildAt(0); while (first.getBottom() < listTop) {//顶部view移除屏幕时 AbsListView.LayoutParams layoutParams = (LayoutParams) first.getLayoutParams(); if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) { recycleBin.addScrapView(first, mFirstPosition); //回收view } detachViewFromParent(first); //从父类中移除 first = getChildAt(0); //这行好像没用啊。。。。 mFirstPosition++; } } else { // shifted items down View first = getChildAt(0); // may need to pan views into top while ((first.getTop() > listTop) && (mFirstPosition > 0)) {//顶部view上部有空间时添加view。 first = addViewAbove(first, mFirstPosition); mFirstPosition--; } // may have brought the very first child of the list in too far and // need to shift it back if (first.getTop() > listTop) {//到达第一个view offsetChildrenTopAndBottom(listTop - first.getTop()); } int lastIndex = getChildCount() - 1; View last = getChildAt(lastIndex); // bottom view may be panned off screen while (last.getTop() > listBottom) {//底部view移除屏幕的情况 AbsListView.LayoutParams layoutParams = (LayoutParams) last.getLayoutParams(); if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) { recycleBin.addScrapView(last, mFirstPosition+lastIndex); } detachViewFromParent(last); last = getChildAt(--lastIndex); } } } |
从以上代码可以看出,Android中view回收的计算是其父view中不再显示的,如果scrollview中包含了一个wrap_content属性的listview,里面的内容并不会有任何回收,引起listview 的getheight函数获取的是一个足以显示所有内容的高度。
3.2 AbsListView
3.2.1 obtainView
(int position, boolean[] isScrap)(2227)
Get a view and have it show the data associated with the specified position. 当这个方法被调用时,说明Recycle bin中的view已经不可用了,那么,现在唯一的方法就是,convert一个老的view,或者构造一个新的view。
position: 要显示的位置
isScrap: 是个boolean数组, 如果view从scrap heap获取,isScrap [0]为true,否则为false。
isScrap[0] = false; View scrapView; scrapView = mRecycler.getTransientStateView(position); if (scrapView == null) { // 查看回收站中是否有废弃无用的View,如果有,则使用它,无需New View。 scrapView = mRecycler.getScrapView(position); } View child; if (scrapView != null) { //此时说明可以从回收站中重新使用scrapView。 child = mAdapter.getView(position, scrapView, this); if(child.getImportantForAccessibility()== IMPORTANT_FOR_ACCESSIBILITY_AUTO) { child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } if (child != scrapView) { //如果重用的scrapView和adapter获得的view是不一样的,将scrapView进行回收 mRecycler.addScrapView(scrapView, position);// scrapView 仍然放入回收站 if (mCacheColorHint != 0) { child.setDrawingCacheBackgroundColor(mCacheColorHint); } } else { //如果重用的view和adapter获得的view是一样的,将isScrap[0]值为true,否则默认为false isScrap[0] = true; // Clear any system-managed transient state so that we can // recycle this view and bind it to different data. if (child.isAccessibilityFocused()) { child.clearAccessibilityFocus(); } child.dispatchFinishTemporaryDetach(); } }else {//回收站中没有拿到数据,就只能够自己去inflate一个xml布局文件,或者new一个view child = mAdapter.getView(position, null, this); //当getview中传入的 converView=null的时候会在getView的方法中进行新建这个view if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } if (mCacheColorHint != 0) { child.setDrawingCacheBackgroundColor(mCacheColorHint); } } |
3.2.2 trackMotionScroll
(int deltaY, int incrementalDeltaY)(4991)
监视滑动动作
deltaY: Amount to offset mMotionView. This is the accumulated delta since the motion began. 正数表示向下滑动。
incrementalDeltaY :Change in deltaY from the previous event.
....... // 滚动时,不在可见范围内的item放入回收站。。。。。。。 if (down) { int top = -incrementalDeltaY; if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) { top += listPadding.top; } for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); if (child.getBottom() >= top) { break; } else { count++; int position = firstPosition + i; if (position >= headerViewsCount && position < footerViewsStart) { // The view will be rebound to new data, clear any // system-managed transient state. if (child.isAccessibilityFocused()) { child.clearAccessibilityFocus(); } mRecycler.addScrapView(child, position);//放入回收站 } } } } else { int bottom = getHeight() - incrementalDeltaY; if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) { bottom -= listPadding.bottom; } for (int i = childCount - 1; i >= 0; i--) { final View child = getChildAt(i); if (child.getTop() <= bottom) { break; } else { start = i; count++; int position = firstPosition + i; if (position >= headerViewsCount && position < footerViewsStart) { // The view will be rebound to new data, clear any // system-managed transient state. if (child.isAccessibilityFocused()) { child.clearAccessibilityFocus(); } mRecycler.addScrapView(child, position);//放入回收站 } } } } |
4. 用到的关键类
4.1 ViewType的使用
在listview中当有多种viewtype的时候,在adapter中继承设置getItemViewType方法可以更有效率 。示例如下:
....... private static final int TYPE_ITEM = 0; private static final int TYPE_SEPARATOR = 1; private static final int TYPE_MAX_COUNT = TYPE_SEPARATOR + 1; @Override public int getItemViewType(int position) { return mSeparatorsSet.contains(position) ? TYPE_SEPARATOR : TYPE_ITEM; } @Override public int getViewTypeCount() { return TYPE_MAX_COUNT; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; int type = getItemViewType(position); if (convertView == null) { holder = new ViewHolder(); switch (type) { case TYPE_ITEM: convertView = mInflater.inflate(R.layout.item1, null); holder.textView = (TextView)convertView.findViewById......; break; case TYPE_SEPARATOR: convertView = mInflater.inflate(R.layout.item2, null); holder.textView = (TextView)convertView.findViewById......; break; } convertView.setTag(holder); } else { holder = (ViewHolder)convertView.getTag(); } ........ } |
如果实现了RecyclerListener接口,当一个View由于ListView的滑动被系统回收到RecycleBin的mScrapViews数组时,会调用RecyclerListener中的onMovedToScrapHeap(View view)方法。RecycleBin相当于一个临时存储不需要显示的那部分Views的对象,随着列表滑动,这些Views需要显示出来的时候,他们就被从RecycleBin中拿了出来,RecycleBin本身并不对mScrapViews中的对象做回收操作。
于是在工程里,为ListView添加RecyclerListener接口,并在onMovedToScrapHeap方法中释放ListItem包含的Bitmap资源,这样可以极大的减少内存占用。
4.2 TransientStateView
用来标记这个view的瞬时状态,用来告诉app无需关心其保存和恢复。从注释看,这种具有瞬时状态的view,用于在view动画播放等情况中。
ListView回收机制相关分析的更多相关文章
- Android学习笔记之ListView复用机制
PS:满打满算,差不多三个月没写博客了...前一阵忙的不可开交...总算是可以抽出时间研究研究其他事情了... 学习内容: 1.ListView的复用机制 2.ViewHolder的概念 1.List ...
- Android AdapterView 源码分析以及其相关回收机制的分析
忽然,发现,网上的公开资料都是教你怎么继承一个baseadapter,然后重写那几个方法,再调用相关view的 setAdpater()方法, 接着,你的item 就显示在手机屏幕上了.很少有人关注a ...
- .net垃圾回收机制编程调试试验
1. 什么是CLR GC? 它是一个基于引用跟踪和代的垃圾回收器. 从本质上,它为系统中所有活跃对象都实现了一种引用跟踪模式,如果一个对象没有任何引用指向它,那么这个对象就被认为是垃圾对象,并且可以被 ...
- JavaScript具有自动垃圾回收机制
JavaScript具有自动垃圾回收机制 原理: 找出那些不再继续使用的变量,然后释放其占用的内存. 正常的生命周期: 局部变量指在函数执行的过程中存在.而在这个过程中,会为局部变量在栈或 ...
- JVM学习(4)——全面总结Java的GC算法和回收机制
俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及到的知识点总结如下: 一些JVM的跟踪参数的设置 Java堆的分配参数 -Xmx 和 –Xms 应该保持一个什么关系,可以让系统的 ...
- java垃圾回收机制
1 .垃圾回收机制(GC)垃圾回收就是回收内存中不再使用对象:(1)垃圾回收的步骤:1)查找内存中不再使用的对象:2)释放这些对象所占用的内存:(2)查找内存中不再使用的对象方法:1)引用计数法如果一 ...
- 垃圾回收机制GC知识再总结兼谈如何用好GC
一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对资源(内存使用)管理的方式,常见的一般 ...
- 【转载】Java垃圾回收机制
原文地址:http://www.importnew.com/19085.html Java垃圾回收机制 说到垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联 ...
- 【转】深入理解 Java 垃圾回收机制
深入理解 Java 垃圾回收机制 一.垃圾回收机制的意义 Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再 ...
随机推荐
- 正则表达式和grep
本章主要通过一些应用实例,来对正则表达式进行说明. 1.正则表达式 正则表达式就是字符串的表达式.它能通过具有意义的特殊符号表示一列或多列字符串.grep是linux系统下常用的正则表达式工具,可以使 ...
- json的好处-新一代数据传输利器
JSON是一种轻量级的数据交换格式!和xml一样. 为什么不XML XML的冗余太大,不过XML阅读起来比较方面,所以并没有被json完全取代,很多时候都是并存.比如sina微博的开发平台有一个JSO ...
- Linq编程小趣味爱因斯坦谜题
最近看到一个比较老的题目,题目----在一条街上,有5座房子,喷了5种颜色,每个房里住着不同国籍的人,每个人喝不同的饮料,抽不同品牌的香烟,养不同的宠物,问题---谁养鱼? 以前没事还做过这个题,现在 ...
- python3 操作sqlSever
相关代码如下: #coding =utf-8 import os import pyodbc import time class SqlDb: def __init__(self, server='D ...
- DigCSDN介绍首页
recrefer=SE_D_DigCSDN">360手机助手下载地址 兴许平台会陆续登陆上线的,大家敬请期待 最后由于屏幕适配和分享链接的问题,导致最后的公布时间延误了好几天--- 今 ...
- 使用GCD创建单例
+ (KKTextHUB *)sharedTextHUB { static KKTextHUB *sharedHub = nil; static dispatch_once_t onceToken; ...
- CAE医疗综合视听中心管理系统
http://caehealthcare.com/eng/audiovisual-solutions/learning-space https://vimeo.com/108897296http:// ...
- Test Double
我不知道Test Double翻译成中文是什么,测试替身?Test Double就像是陈龙大哥电影里的替身,起到以假乱真的作用.在单元测试时,使用Test Double减少对被测对象的依赖,使得测试更 ...
- mavern安装方法
Installation Instructions Maven is a Java tool, so you must have Java installed in order to proceed. ...
- js 自定义方法
js自定义封装方法 CreateTime--2016年10月16日15:18:18Author:Marydon 声明:该文章主要是记录了需要使用javascript实现对日常需要的方法进行封装,封 ...