内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。
内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
memory leak会最终会导致out of memory!
内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。
内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出!比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出
以发生的方式来分类,内存泄漏可以分为4类:
1 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
2 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或 *** 作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
3 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。
4 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。
从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到
内存溢出的原因以及解决方法
引起内存溢出的原因有很多种,小编列举一下常见的有以下几种:
1内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
2集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
3代码中存在死循环或循环产生过多重复的对象实体;
4使用的第三方软件中的BUG;
5启动参数内存值设定的过小
内存溢出的解决方案:
第一步,修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)
第二步,检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。
第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。
重点排查以下几点:
1检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
2检查代码中是否有死循环或递归调用。
3检查是否有大循环重复产生新对象实体。
4检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
5检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。
第四步,使用内存查看工具动态查看内存使用情况
1在studio 最上面的导航栏里面找到 build ,然后点击build,
2然后找到 "Edit Libraries and Dependencies" 点击,
3,在d出来的框右上角有个加号,点击
4,选择Library Dependency
5,输入recycler
6,回车或者点击搜索,然后选择结果就行了
you can also add lib/dependencies from android studio menu
click on "Build" -> "Edit Libraries and Dependencies" then click on "+" button on right side
search any lib
example search "recycler"
then select "comandroidsupport:recyclerview-v7:xxx" from list and your done
今天开始讲RecycleView的系列教程。分割线,分组,局部刷新,动态添加,缓存原理,抖音效果,瀑布流。嵌套,动画等等
RecyclerView的分割线是通过canvas和设置item偏移画出来的需要知道2个方法
getItemOffsets()和onDraw方法
getItemOffsets 是针对每一个 ItemView
onDraw:遍历,进行颜色修改
我们可以看到自定义的 TestDividerItemDeoration 只实现了一个方法 getItemOffsets()。方法里面有四个参数。
Rect outRect
View view
RecyclerView parent
RecyclerViewState state
绿色区域代表 RecyclerView 中的一个 ItemView,而外面橙色区域也就是相应的 outRect,也就是 ItemView 与其它组件的偏移区域,等同于 margin 属性,通过复写 getItemOffsets() 方法,然后指定 outRect 中的 top、left、right、bottom 就可以控制各个方向的间隔了。
这实现了简单的分隔线效果,但这种方法分隔线的效果只能取决于背景色,如果我要定制分割线的颜色呢?这个时候就要 onDraw()。
————————————————
源码分析:在recycleview中的
分割线要注意,没有颜色,默认是白色的,会看不出来
第一种方案,通过
getItemOffsets()方法进行分割线!
判断是否是第一个,最后一个,是单个还是双个,是什么类型
/
分割线要注意,没有颜色,默认是白色的,会看不出来
@param outRect
@param view
@param parent
@param state
/
private void testItemOffset(Rect outRect, View view, RecyclerView parent, RecyclerViewState state) {
int childAdapterPosition = parentgetChildAdapterPosition(view);
if (childAdapterPosition ==0) {
outRectset(0, 20, 0, 20);
}else {
outRectset(0, 0, 0, 20);
}
}
第二种方案:ondraw()
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerViewState state) {
superonDraw(c, parent, state);
int childCount = parentgetChildCount();
for (int i =0; i < childCount; i++) {
View view = parentgetChildAt(i);
int index = parentgetChildAdapterPosition(view);
//第一个ItemView不需要绘制
if (index ==0) {
continue;
}
float dividerTop = viewgetTop() -mDividerHeight;
float dividerLeft = parentgetPaddingLeft();
float dividerBottom = viewgetTop();
float dividerRight = parentgetWidth() - parentgetPaddingRight();
cdrawRect(dividerLeft, dividerTop, dividerRight, dividerBottom, mPaint);
}
}
GridLayoutManager布局item左右间距均等
思路分析
首先,我们知道,对于 GridLayoutmanager ,当我们设置的 spancount 为 3 的时候,那么每个 item 的最大宽度为 itemMaxW = recycylerW / spancount = recycylerW / 3
假设我们 spancount 为 3,那么在不设置 itemDercation 的情况下它的分布是这样的,可以看到第一列与最后一行的距离是不一样的
GridVIew出现的问题:本来固定item高度和宽度
1分割线有,不是理想的,左右均等
2上下没有分割线
源码得到:
按上面分析的源码,我们可以知道,调用outRectset(int left, int top, int right, int bottom)方法时,left一直为0,right一直为divider的宽度,而每一项item的宽度都要减去(left+right)大小,
left一直为0,right一直为divider的宽度
左上右下到底是什么的值?
计算每一个item移动的距离,左边和右边的移动距离
计算分析:
1左边的分割线宽度为sW (已知)
2每个显示item的宽度,布局定义的itemWidth
3 总共分割线宽度:totalDivider=屏幕宽度-spanCountitemWidth
4列之间的分割线宽度为dw =(屏幕宽度-spanCountitem-2sW )/(spantcount-1)
5每个item需要留出的空间 ew=totalDivider/spanCount(即paddingLeft+paddingRight)
left: 左边的间距值(绝对值,差值)
right:右边的间距值
每个item移动的距离:
第一个Item:L0=sW R0=eW-sW
第二个Item:L1=dW-R0=dW-eW+sW R1=eW-L1=2eW-dW-sW
第三个Item:L2=dW-R1=2(dW-eW)+sW R2=eW-L2=3eW-2dW-sW
得出公式:
Ln=(position%spanCount)(dw-ew)+sw
Rn=ew-Ln
总结:得到3个值dw,ew, sw的值
sw:左边的距离
ew:每个的平均的分割线
dw: 列之间的分割线宽度
int firstLastSpace =50;//最左边的分割线宽度
@SuppressLint("LongLogTag")
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerViewState state) {
supergetItemOffsets(outRect, view, parent, state);
count++;
outRecttop =20;
mDividerHeight =0;
int itemWidth =dip2px(context, 100);
int screenWidth = getScreenWidth(context);
int dw = (screenWidth -3 itemWidth -2 firstLastSpace) /2;//最终计算出这个padding值
//误区:中间的分割线的总距离,左右可能是不等的
int totalDivder = screenWidth -3 itemWidth;
Logd("TestDividerItemDecoration", "totalDivder" + totalDivder);
int eachDivder = totalDivder /3;
int itemPosition = ((RecyclerViewLayoutParams) viewgetLayoutParams())getViewLayoutPosition();
//不要用for循环
outRectleft = (itemPosition %3) (dw - eachDivder) +firstLastSpace;
outRectright = eachDivder - outRectright;
}
错误的思路:
//误区:中间的分割线的总距离,左右可能是不等的
//不要用for循环
int firstLastSpace =50;//最左边的分割线宽度
@SuppressLint("LongLogTag")
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerViewState state) {
supergetItemOffsets(outRect, view, parent, state);
count++;
outRecttop =20;
mDividerHeight =0;
int itemWidth =dip2px(context, 100);
int screenWidth = getScreenWidth(context);
int padding = (screenWidth -3 itemWidth -2 firstLastSpace) /4;//最终计算出这个padding值
//不能这么算,必须保证每个item的分割线一样才行。
Logd("TestDividerItemDecoration", "getItemOffsets" +count +"item宽度:" + itemWidth +"padding" + padding);
//仅仅计算左边和右边的距离
int childCount = parentgetChildCount();
for (int i =0; i < childCount; i++) {
if (i %3 ==0) {//最左边的item
outRectleft =firstLastSpace;
outRectright = padding;
}else if (i %3 ==1) {
outRectleft = padding;
outRectright = padding;
}else if (i %3 ==2) {
outRectleft = padding;
outRectright =firstLastSpace;
}
}
}
瀑布流的设置:
int spanIndex = layoutParamsgetSpanIndex();
public class FeedDecorationextends RecyclerViewItemDecoration {
private HomePageCardAdaptermHomePageCardAdapter;
public FeedDecoration(HomePageCardAdapter mHomePageCardAdapter) {
thismHomePageCardAdapter = mHomePageCardAdapter;
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerViewState state) {
if (mHomePageCardAdapter ==null) {
return;
}
if (mHomePageCardAdaptergetItemViewType(parentgetChildAdapterPosition(view)) == HomePageMultipleCardHOMEPAGE_MULTIPLE_CARD_TYPE_FITNESS_FEED) {
StaggeredGridLayoutManagerLayoutParams layoutParams = (StaggeredGridLayoutManagerLayoutParams) viewgetLayoutParams();
int spanIndex = layoutParamsgetSpanIndex();
if (spanIndex ==0) {
outRectset(DensityUtildip2px(ShadowAppcontext(), 14), 0, DensityUtildip2px(ShadowAppcontext(), 5), DensityUtildip2px(ShadowAppcontext(), 10));
}else {
outRectset(DensityUtildip2px(ShadowAppcontext(), 5), 0, DensityUtildip2px(ShadowAppcontext(), 14), DensityUtildip2px(ShadowAppcontext(), 10));
}
}
}
}
demo地址: >
在内网环境中我们经常会使用NAS或者Samba在Windows中映射网络驱动器,方便局域网用户实时共享交换数据。但当存储在网络或映射网络上的任何文件被删除时,该文件将被永久删除。它不会去到本地计算机回收站,也不会去到服务器的回收站,我通过google在mydigitallife和microsoft technet中搜索到很多方法,但针对不同 *** 作系统且涉及到域用户管理的复杂情况下,单纯的依赖注册表修改可能已经支撑不住需求的膨胀了。在所有的方法中使用Network Recycle Bin可以轻松解决映射网络驱动器上的回收站。
2018年04月20日 - 初稿
阅读原文 - >
以上就是关于内存溢出和内存泄漏的区别,产生原因以及解决方案全部的内容,包括:内存溢出和内存泄漏的区别,产生原因以及解决方案、Android Studio 3.6如何使用RecycleView、1.Android recycleView万能分隔线 GridLayoutManager布局item左右间距均等(最易懂)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)