内存溢出和内存泄漏的区别,产生原因以及解决方案

内存溢出和内存泄漏的区别,产生原因以及解决方案,第1张

内存溢出 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左右间距均等(最易懂)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/9478161.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-28
下一篇 2023-04-28

发表评论

登录后才能评论

评论列表(0条)

保存