内存泄露:指程序中动态分配内存给一些临时对象,可是对象不会被GC所回收,它始终占用内存。即被分配的对象可达但已无用。
内存溢出:指程序运行过程当中没法申请到足够的内存而致使的一种错误。内存溢出一般发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的状况。
从定义上能够看出内存泄露是内存溢出的一种诱因,可是不是惟一因素。java
Runtime.getRuntime().freeMemory()表示当前还有多少空闲内存数据库
package com.one.util; public class Hello { public static void main(String[] args) { System.out.println("free内存:" + Runtime.getRuntime().freeMemory() / 1024 / 1024); String[] aaa = new String[2000000]; for (int i = 0; i < 2000000; i++) { aaa[i] = new String("aaa"); } System.out.println("free内存:" + Runtime.getRuntime().freeMemory() / 1024 / 1024); } }
此时结果以下所示
网络
好比下面的代码,这里的object实例,其实咱们指望它只做用于method1()方法中,且其余地方不会再用到它,可是,当method1()方法执行完成后,object对象所分配的内存不会立刻被认为是能够被释放的对象,只有在Simple类建立的对象被释放后才会被释放,严格的说,这就是一种内存泄露。socket
public class Simple { Object object; public void method1(){ object = new Object(); //...其余代码 } }
怎么解决上面的问题呢,加上下面的蓝色代码注释就行了ide
public class Simple { Object object; public void method1(){ object = new Object(); //...其余代码 // 蓝色代码注释开始 object = null; // 蓝色代码注释结束 } }
好比下面的代码
由于你已经在下面的蓝色代码注释里面进行company=null了,因此下面的list集合里面的数据都是无用的了,可是此时list集合里面的全部元素都不会进行垃圾回收测试
package com.four; import java.util.ArrayList; import java.util.List; public class Hello { public static void main(String[] args) { List<Company> list = new ArrayList<Company>(); int i=0; for(int j=0;j<10;j++){ Company company = new Company(); company.setName("ali"); list.add(company); // 蓝色代码注释开始 company = null; // 蓝色代码注释结束 } System.gc(); while(true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("已经测试了"+(++i)+"秒"); } } } class Company { private String name; @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("回收Comapny"); } public void setName(String name) { this.name = name; } public String getName() { return name; } }
怎么解决上面的问题呢,就是把上面的list集合变量也变成null,好比加上下面的红色代码注释this
package com.one.util; import java.util.ArrayList; import java.util.List; public class Hello { public static void main(String[] args) { List<Company> list = new ArrayList<Company>(); int i = 0; for (int j = 0; j < 10; j++) { Company company = new Company(); company.setName("ali"); list.add(company); // 蓝色代码注释开始 company = null; // 蓝色代码注释结束 } // 红色代码注释开始 list = null; // 红色代码注释结束 System.gc(); while (true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("已经测试了" + (++i) + "秒"); } } } class Company { private String name; @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("回收Comapny"); } public void setName(String name) { this.name = name; } public String getName() { return name; } }
此时结果以下所示,能够看出来集合里面的Company变量都回收了
code
什么意思呢,
就好比ArrayList里面的pop(),若是是下面的写法就会形成内存泄漏,由于下面的elementData[--size]这个元素移除以后,并无进行设置成null对象
public E pop(){ if(size == 0) return null; else return (E) elementData[size]; }
因此上面的代码应该变成下面这样,此时注意下面的蓝色代码注释里面的size值比下面的红色代码注释里面的size小1blog
public E pop(){ if(size == 0) return null; else{ // 红色代码注释开始 E e = (E) elementData[--size]; // 红色代码注释结束 // 蓝色代码注释开始 elementData[size] = null; // 蓝色代码注释结束 return e; } }
好比数据库链接(dataSourse.getConnection()),网络链接(socket)和io链接,这些连接在使用的时候,除非显式的调用了其close()方法(或相似方法)将其链接关闭,不然是不会自动被GC回收的。其实缘由依然是长生命周期对象持有短生命周期对象的引用。因此咱们常常在网上看到在链接调用结束的时候要进行调用close()进行关闭,这样能够回收不用的内存对象,增长可用内存。
能看到这里的同窗,就帮忙点个推荐吧吧,Thanks♪(・ω・)ノ