参考YourAaron的博客,网址:https://blog.csdn.net/weter_drop/article/details/89387564
参考:https://www.jianshu.com/p/420bacba1b12
解决内存泄漏的一个方法,就是尽量降低变量的作用域,以及时时把对象复制为可清理对象(null)
public class Simple {
Object object;
void method () {
object = new Object();
}
}
严格意义上就是一种内存泄漏,因为object不在被使用,但他不会立即被回收,而是等到Simple对象被释放的时候。
这样写,可以。
public class Simple {
Object object;
void method () {
Object object = new Object();
//使用Object
object = null;
}
}
把Object定义为局部变量,并在最后赋值为null
同时,ArrayList的pop方法:
public E pop(){
if(size == 0)
return null;
else{
E e = (E) elementData[--size];
elementData[size] = null;
return e;
}
}
容器使用时的内存泄漏
Vector vector = new Vector();
for (int i = 1; i<100; i++)
{
Object object = new Object();
vector.add(object);
object = null;
}
//...对vector的操作
//...与vector无关的其他操作
}
这里其实只是会造成短暂的内存泄漏,在method方法结束后还是会把回收的,更好的写法是:
Vector vector = new Vector();
for (int i = 1; i<100; i++)
{
Object object = new Object();
vector.add(object);
object = null;
}
//...对vector的操作
vector = null;
//...与vector无关的其他操作
}
在各种IO或者数据库连接中,都需要在最后通过close()方法释放对象,这里也是长对象引用短对象是造成的内存泄漏
SessionFactory factory = new SessionFactory();
try {
Session session = factory.connect();
} finally{
session.close();
}
这里必须用close关闭连接,因为SessionFactory是长对象,session是短对象。
可以看到WeakHashMap的key是弱引用,ThreadLocal的key也是用的弱引用,但是WeakHashMap在被GC回收时value也会被回收了,而ThreadLocal则不会,ThreadLocal必须显示的调用一下remove方法才能将value的值给清空。
在两个的源码中可以看到,ThreadLocal里面并没有一个接受对象被GC回收后通知的ReferenceQueue,所以就算key被回收了,value也是存在的,并不会和WeakHashMap一样,在key被清空后,可以使用ReferenceQueue这个队列接受被GC的通知,然后把value也自己给清空。
-Xmn10M 年轻带10M -XX:SurvivorRatio=8,此为Eden区域和Survivor区域(From幸存区或To幸存区)的比例,默认为8,也就是说Eden占新生代的8/10,From幸存区和To幸存区各占新生代的1/10。
当GC增加时,或者内存占用的不断增加,序性能的降低就会表现出来,严重时可导致内存泄漏
当进行大量的pop操作时,由于引用未进行置空,gc是不会释放的。
从上图中看以看出,如果栈先增长,在收缩,那么从栈中弹出的对象将不会被当作垃圾回收,即使程序不再使用栈中的这些队象,他们也不会回收,因为栈中仍然保存这对象的引用,俗称过期引用,这个内存泄露很隐蔽。
解决方法:
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null;
return result;
}
原始为:
import java.util.Arrays;
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[--size];
}
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
内存泄漏的另一个常见来源是缓存,一旦你把对象引用放入到缓存中,他就很容易遗忘,对于这个问题,可以使用WeakHashMap代表缓存,此种Map的特点是,当除了自身有对key的引用外,此key没有其他引用那么此map会自动丢弃此值
WeakHashMap就是一个HashMap,只不过它的key继承了WeakReference表示key是一个弱引用,在GC时就会被回收。
其中WeakHashMap
输出为:
String引用ref1,ref2,ref3,ref4 消失
WeakHashMap GC之前
obejct2=chaheObject2
obejct1=chaheObject1
WeakHashMap GC之后
HashMap GC之前
obejct4=chaheObject4
obejct3=chaheObject3
HashMap GC之后
obejct4=chaheObject4
obejct3=chaheObject3
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;
public class Test3 {
static Map wMap = new WeakHashMap();
static Map map = new HashMap();
public static void main(String[] args) {
init();
testWeakHashMap();
testHashMap();
}
public static void init(){
String ref1= new String("obejct1");
String ref2 = new String("obejct2");
String ref3 = new String ("obejct3");
String ref4 = new String ("obejct4");
wMap.put(ref1, "chaheObject1");
wMap.put(ref2, "chaheObject2");
map.put(ref3, "chaheObject3");
map.put(ref4, "chaheObject4");
System.out.println("String引用ref1,ref2,ref3,ref4 消失");
}
public static void testWeakHashMap(){
System.out.println("WeakHashMap GC之前");
for (Object o : wMap.entrySet()) {
System.out.println(o);
}
try {
System.gc();
TimeUnit.SECONDS.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("WeakHashMap GC之后");
for (Object o : wMap.entrySet()) {
System.out.println(o);
}
}
public static void testHashMap(){
System.out.println("HashMap GC之前");
for (Object o : map.entrySet()) {
System.out.println(o);
}
try {
System.gc();
TimeUnit.SECONDS.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("HashMap GC之后");
for (Object o : map.entrySet()) {
System.out.println(o);
}
}
}