Java中什么时候会发生android中的内存泄漏漏

java中会存在内存泄漏吗,请简单描述
所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。java中有
垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象
将自动被垃圾回收器从内存中清除掉。由于Java 使用有向图的方式进行垃圾回收管理
,可以消除引用循环的问题,例如有两个对象,相互引用,只要它们和根进程不可达的
,那么GC也是可以回收它们的,例如下面的代码可以看到这种情况的内存回收:
package com.huawei.
import java.io.IOE
public class GarbageTest {
public static void main(String[] args) throws IOException
// TODO Auto-generated method stub
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("has exited gcTest!");
System.in.read();
System.in.read();
System.out.println("out begin gc!");
for(int i=0;i&100;i++)
System.gc();
System.in.read();
System.in.read();
private static void gcTest() throws IOException {
System.in.read();
System.in.read();
Person p1 = new Person();
System.in.read();
System.in.read();
Person p2 = new Person();
p1.setMate(p2);
p2.setMate(p1);
System.out.println("before exit gctest!");
System.in.read();
System.in.read();
System.gc();
System.out.println("exit gctest!");
private static class Person
byte[] data = new byte[];
Person mate =
public void setMate(Person other)
java中的内存泄露的情况:长生命周期的对象持有短生命周期对象的引用就很可能发生
内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用
而导致不能被回收,这就是java中内存泄露的发生场景,通俗地说,就是程序员可能创
建了一个对象,以后一直不再使用这个对象,这个对象却一直被引用,即这个对象无用
但是却无法被垃圾回收器回收的,这就是java中可能出现内存泄露的情况,例如,缓存
系统,我们加载了一个对象放在缓存中(例如放在一个全局map对象中),然后一直不再
使用它,这个对象一直被缓存引用,但却不再被使用。
检查java中的内存泄露,一定要让程序将各种分支情况都完整执行到程序结束,然后看
某个对象是否被使用过,如果没有,则才能判定这个对象属于内存泄露。
如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长
期引用了,即使那个外部类实例对象不再被使用,但由于内部类持久外部类的实例对象
,这个外部类对象将不会被垃圾回收,这也会造成内存泄露。
下面内容来自于网上(主要特点就是清空堆栈中的某个元素,并不是彻底把它从数组中
拿掉,而是把存储的总数减少,本人写得可以比这个好,在拿掉某个元素时,顺便也让
它从数组中消失,将那个元素所在的位置的值设置为null即可):
我实在想不到比那个堆栈更经典的例子了,以致于我还要引用别人的例子,下面的例子
不是我想到的,是书上看到的,当然如果没有在书上看到,可能过一段时间我自己也想
的到,可是那时我说是我自己想到的也没有人相信的。
& & public class Stack
& & private Object[]
elements=new Object[10];
& & private int size =
& & public void push(Object
& & ensureCapacity();
& & elements[size++] =
& & public Object
& & if( size == 0)
& & throw new
EmptyStackException();
& & return
elements[--size];
& & private void
ensureCapacity(){
& & if(elements.length ==
& & Object[] oldElements =
& & elements = new Object[2
* elements.length+1];
System.arraycopy(oldElements,0, elements, 0, size);
上面的原理应该很简单,假如堆栈加了10个元素,然后全部弹出来,虽然堆栈是空
的,没有我们要的东西,但是这是个对象是无法回收的,这个才符合了内存泄露的两个
条件:无用,无法回收。
但是就是存在这样的东西也不一定会导致什么样的后果,如果这个堆栈用的比较少
,也就浪费了几个K内存而已,反正我们的内存都上G了,哪里会有什么影响,再说这个
东西很快就会被回收的,有什么关系。下面看两个例子。
& & public class Bad{
& & public static Stack
s=Stack();
& & static{
& & s.push(new
Object());
& & s.pop();
//这里有一个对象发生内存泄露
& & s.push(new Object());
//上面的对象可以被回收了,等于是自愈了
因为是static,就一直存在到程序退出,但是我们也可以看到它有自愈功能,就是
说如果你的Stack最多有100个对象,那么最多也就只有100个对象无法被回收其实这个
应该很容易理解,Stack内部持有100个引用,最坏的情况就是他们都是无用的,因为我
们一旦放新的进取,以前的引用自然消失!
内存泄露的另外一种情况:当一个对象被存储进HashSet集合中以后,就不能修改这个
对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进
HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象
的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也
会导致无法从HashSet集合中单独删除当前对象,造成内存泄露。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。Java 中会存在内存泄漏吗? - Tapana - 博客园
& & 理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题
( 这也是Java被广泛使用于服务器端编程的一个重要原因);然而
&在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC
&回收也会发生内存泄露。一个例子就是Hibernate的Session一级缓
&存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然
&而这 些对象中可能存在无用的垃圾对象。会,存在无用但可达的对象,这些对象不能被GC 回收,导致耗费内存资源。
& &举个例子:
& &在这个例子中,我们循环申请Object对象,并将所申请的对象放入一个Vector中,
& &如果我们仅仅释放引用本身,那么Vector仍然引用该对象,所以这个对象对GC来
& &说是不可回收的。因此,如果对象加入到Vector后,还必须从Vector中删除,
& &最简单的方法就是将Vector对象设置为null
Vector v=new Vector(5);
for (int i=1;i&10; i++)
Object o=new Object();
& &此时,所有的Object对象都没有被释放,因为变量v引用这些对象。&
& &这时候这些Object就是不可用可达的对象,GC不会帮我们清理的, 这就存在了内存泄露了
本文已收录于以下专栏:
相关文章推荐
java中Throwable这个类可以被作为异常抛出的类,继承它的分为异常Exception和错误Error.
Exception表示程序需要捕捉和处理的的异常;
Error表示系统级别的错误和程...
sleep和wait有什么区别
第一种解释:
功能差不多,都用来进行线程控制,他们最大本质的区别是:sleep()不释放同步锁,wait()释放同步缩.  
   
  还有用法的上的不...
人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..
RuntimeException是java中所有运行时异常的父类,实际运行时出现的都是它的子类,看看RuntimeException的Java doc就可以随便列出几个:
Object ...
equals()反映的是对象或变量具体的值,即两个对象里面包含的值--可能是
  对象的引用,也可能是值类型的值。
  而hashCode()是对象或变量通过哈希算法计算出的哈希值。
  之所以...
会。java导致内存泄露的原因很明确:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中...
Java的一个重要优点就是通过垃圾收集器(Garbage Collection,GC)自动管理内存的回收,程序员不需要通过调用函数来释放内存。因此,很多程序员认为Java不存在内存泄漏问题,或者认为即...
所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。java中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动被垃圾回收器从内存中清除掉。由于Jav...
一般来说内存泄漏有两种情况。一种情况如在C/C++ 语言中的,在堆中的分配的内存,在没有将其释放掉的时候,就将所有能访问这块内存的方式都删掉(如指针重新赋值);另一种情况则是在内存对象已经不需要的时候...
所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。java中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动被垃圾回收器从内存中清除掉。由于Jav...
会。java导致内存泄露的原因很明确:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中...
他的最新文章
讲师:董西成
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)博客分类:
前段时间写了一个java socket相关的程序,大概意思就是client和server是采用socket长连接方式,之间通信都是通过通过ObjectOutputStream和OjbectInputStream来进行写和读操作。
其实以前就很多次的用到过ObjectOutputStream,不过没有详细的琢磨过,这次就想着琢磨一下,主要也是因为我发现程序中存在内存泄漏的问题,通过Jprobe跟踪,排除了别的泄漏因素,最后定位在是在socket这里发生了泄漏,具体情况下面进行分析。
先来说说ObjectOutputStream,通过ObjectOutputStream来进行socket写入,那么会在流中加入Object的信息,也就是说如果想要是跨平台的socket通信那么可能会带来一些问题,因为数据流中加入的是java特有的信息,class类型以及成员变量的类型信息,同样通过ObjectInputStream来读取也有相应的规则来进行解析。
下面我们来看一下写入的信息,首先有一个简单的类
class MyObject implements Serializable {
private static final long serialVersionUID = -2080544L;
String str1;
String str2;
我们通过ObjectOutputStream来把该类写入文件中,查看一下写入的内容
? sr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test1t test2q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ 
我们可以看到写入的内容中包含了写入类的类型以及成员变量信息,当然关于插入的内容,我们可以覆盖ObjectOutputStream类的writeStreamHeader()方法来实现插入我们自定义的内容,当然如果这样做的话,我们就必须对ObjectInputStream类进行重写
上面是一些题外话,下面回到正题,关于我标题中提到的有内存泄漏的问题。为了更清晰直观的说明该问题,我又写了一个很简单的测试,代码如下:
FileOutputStream fos = new FileOutputStream("c:\\test.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
MyObject myObj = new MyObject();
myObj.str1 = "test1";
myObj.str2 = "test2";
for (int i = 0; i & 20; i++) {
oos.writeObject(myObj);
oos.writeObject(myObj);
fos.close();
我在这里循环了20次,那么大家可以猜想一下文件中会是什么内容,可能会有人认为是我刚才在上面贴出的内容重复20遍,起初我也是这么认为的,但事实不是这么回事。
我现在更改一下程序,不再循环,只写入一次,那么写入的内容是
? sr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test1t test2q ~ 
? sr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test1t test2q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ 
sr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test1t test2q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ 
这样的测试我们还是不够清晰,下面我们让他每次循环写入的对象的属性都不相同,我们这样修改一下代码
FileOutputStream fos = new FileOutputStream("c:\\test.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
for (int i = 0; i & 10; i++) {
MyObject myObj = new MyObject();
myObj.str1 = "test1" +
myObj.str2 = "test2" +
oos.writeObject(myObj);
oos.writeObject(myObj);
fos.close();
那么这个时候文件里的内容是什么呢,我们再来看一下
? sr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test10t test20q ~ sq ~
t test11t test21q ~ sq ~
t test12t test22q ~ sq ~
t test13t test23q ~ sq ~
t test14t test24q ~ sq ~
t test15t test25q ~ sq ~
t test16t test26q ~ sq ~
t test17t test27q ~ sq ~
t test18t test28q ~ sq ~
t test19t test29q ~ 
这样就显而易见了,我们虽然写入了10次,但是不会每次写入都会插入写入对象和成员变量类型的信心,而是在第一次写入的时候插入一些头信息,以后再写就不会再插入了。这实际是java做的优化,通过该优化从而减少socket传输的开销。
那么会有人问了,你说的内存泄漏的问题呢,写到这里,我想应该有人已经看出问题来了,它之所以可以这么做优化,前提是持有MyObject的引用,也就是说,不会释放掉MyObject的引用。现在明白了吧,如果你是长连接的方式,ObjectOutputStream会一直持有你以前发送过的对象的引用,从而导致jvm在进行垃圾回收的时候不能回收之前发送的对象的实例,经过漫长时间的运行,最终导致内存溢出了。这一点从我通过Jprobe跟踪也得到了印证。
下面我们来谈谈如何避免该问题,说着这里我们就得提到ObjectOutputStream的reset方法了,JDK文档中是这么解释该方法的:
“重置将丢弃已写入流中的所有对象的状态。重新设置状态,使其与新的 ObjectOutputStream 相同。将流中的当前点标记为 reset,相应的 ObjectInputStream 也将在这一点重置。以前写入流中的对象不再被视为正位于流中。它们会再次被写入流。”
就是说调用reset那么就丢弃所持有对象的状态(也就是释放掉了对对象的应用),同时会在流中设置reset标识。
还是之前那个例子,我们来修改一下代码,在每次写入后都调用一下reset方法
FileOutputStream fos = new FileOutputStream("c:\\test.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
for (int i = 0; i & 10; i++) {
MyObject myObj = new MyObject();
myObj.str1 = "test1" +
myObj.str2 = "test2" +
oos.writeObject(myObj);
oos.writeObject(myObj);
oos.reset();
fos.close();
我们再来看一下写入文件内容
? sr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test10t test20q ~ ysr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test11t test21q ~ ysr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test12t test22q ~ ysr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test13t test23q ~ ysr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test14t test24q ~ ysr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test15t test25q ~ ysr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test16t test26q ~ ysr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test17t test27q ~ ysr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test18t test28q ~ ysr com.travelsky.test.MyObjectEUR喳+?^` L str1t Ljava/lang/SL str2q ~ xpt test19t test29q ~ y
这次跟之前不同的,每一次写入都加入了头信息且每一次末尾都加入了y,我想这个标识应该就是reset标识,至于具体是什么,我们没必要深究了。
通过上面一系列的测试,我们大概对Object流有了一定了解,那么具体到我们日常编码中到底该不该调用reset呢,这个我想不能一概而论了,我们通过测试也看到了,在不调用reset的方式下,java的优化对于减轻socket开销还是很可观的,当然代价是有的,那就是直到你调用reset或者是关闭输出流之前,对于发送过的对象的实例是不会释放的。
结论:当然只是我自己的片面之词。如果你的程序需要很长时间的运行,我建议你还是调用reset避免最后内存溢出程序崩溃,但是如果你又要长时间运行,且发送的消息量又很大,那么调用reset无疑会增加开销,那么这个时候最好的做法我觉得是你自己实现一套机制,定时的调用reset或者是定量,比如查看到内存已经涨到一个水平后调用一下,这样既可以避免内存无限的增长下去,又可以减少不少socket通信的开销
anson在这里感谢大家花了这么长时间阅读该文章,希望能给大家带了一些帮助,另外上面的分析都是我个人的理解,肯定存在一定的局限性,大家有什么更深刻的认识,还请大家指出来,我们一起交流,共同进步
浏览: 14331 次
来自: 北京
楼主,请教下socket保持长连接需要怎么实现

我要回帖

更多关于 内存泄漏 的文章

 

随机推荐