当前位置:首页 > 机械智慧 > 正文

Java 中的内存溢出和内存泄露是什么?我给你举个有味道的例子​

JAVA中的内存溢出和内存泄露分别是什么,有什么联系和区别,让我们来看一看。内存泄漏内存溢出1.内存泄漏(memoryleak)申请了内存用完了不释放,比如一共有1024M的内存,分配了521M的内存一直不回收,那么可以用的内存只有521M了,仿佛泄露掉了一部分;通俗一点讲的话,内存泄漏就是【占着茅...

JAVA中的内存溢出和内存泄露分别是什么,有什么联系和区别,让我们来看一看。内存泄漏内存溢出1.内存泄漏(memoryleak)申请了内存用完了不释放,比如一共有1024M的内存,分配了521M的内存......

JAVA中的内存溢出和内存泄露分别是什么,有什么联系和区别,让我们来看一看。

内存泄漏内存溢出

1.内存泄漏(memoryleak)

申请了内存用完了不释放,比如一共有1024M的内存,分配了521M的内存一直不回收,那么可以用的内存只有521M了,仿佛泄露掉了一部分;

通俗一点讲的话,内存泄漏就是【占着茅坑不拉shi】。

2.内存溢出(outofmemory)

申请内存时,没有足够的内存可以使用;

通俗一点儿讲,一个厕所就三个坑,有两个站着茅坑不走的(内存泄漏),剩下最后一个坑,厕所表示接待压力很大,这时候一下子来了两个人,坑位(内存)就不够了,内存泄漏变成内存溢出了。

可见,内存泄漏和内存溢出的关系:内存泄露的增多,最终会导致内存溢出。

这是一个很有味道的例子。

如上图:

对象X引用对象Y,X的生命周期比Y的生命周期长;

那么当Y生命周期结束的时候,X依然引用着Y,这时候,垃圾回收期是不会回收对象Y的;

如果对象X还引用着生命周期比较短的A、B、C,对象A又引用着对象a、b、c,这样就可能造成大量无用的对象不能被回收,进而占据了内存资源,造成内存泄漏,直到内存溢出。

泄漏的分类

经常发生:发生内存泄露的代码会被多次执行,每次执行,泄露一块内存;

偶然发生:在某些特定情况下才会发生;

一次性:发生内存泄露的方法只会执行一次;

隐式泄露:一直占着内存不释放,直到执行结束;严格的说这个不算内存泄露,因为最终释放掉了,但是如果执行时间特别长,也可能会导致内存耗尽。

导致内存泄漏的常见原因

1.循环过多或死循环,产生大量对象;

2.静态集合类引起内存泄漏,因为静态集合的生命周期和JVM一致,所以静态集合引用的对象不能被释放;下面这个例子中,list是静态的,只要JVM不停,那么obj也一直不会释放。

publicclassOOM{staticListlist=newArrayList();publicvoidoomTests(){Objectobj=newObject();(obj);}}

3.单例模式,和静态集合导致内存泄露的原因类似,因为单例的静态特性,它的生命周期和JVM的生命周期一样长,所以如果单例对象如果持有外部对象的引用,那么这个外部对象也不会被回收,那么就会造成内存泄漏。

4.数据连接、IO、Socket连接等等,它们必须显示释放(用代码close掉),否则不会被GC回收。

try{Connectionconn=null;("");conn=("url","","");Statementstmt=();ResultSetrs=(".");}catch(Exceptione){//异常日志}finally{//1.关闭结果集Statement//2.关闭声明的对象ResultSet//3.关闭连接Connection}

5.内部类的对象被长期持有,那么内部类对象所属的外部类对象也不会被回收。

6.Hash值发生改变,比如下面中的这个类,它的hashCode会随着变量x的变化而变化:

publicclassChangeHashCode{privateintx;@OverridepublicinthashCode(){finalintprime=31;intresult=1;result=prime*result+x;returnresult;}@Overridepublicbooleanequals(Objectobj){if(this==obj)returntrue;if(obj==null)returnfalse;if(getClass()!=())returnfalse;ChangeHashCodeother=(ChangeHashCode)obj;if(x!=)returnfalse;returntrue;}//省略set、get方法}
publicclassHashSetTests{publicstaticvoidmain(String[]args){HashSetChangeHashCodehs=newHashSetChangeHashCode();ChangeHashCodecc=newChangeHashCode();(10);//hashCode=41(cc);(20);//hashCode=51("="+(cc));//(cc);("="+());//size=2}}

可以看到,在测试方法中,当元素的hashCode发生改变之后,就再也找不到改变之前的那个元素了;

这也是String为什么被设置成了不可变类型,我们可以放心地把String存入HashSet,或者把String当做HashMap的key值;

当我们想把自己定义的类保存到散列表的时候,需要保证对象的hashCode不可变。

7.内存中加载数据量过大;之前项目在一次上线的时候,应用启动奇慢直到夯死,就是因为代码中会加载一个表中的数据到缓存(内存)中,测试环境只有几百条数据,但是生产环境有几百万的数据。

最新文章