Java中什么时候会出现内存泄漏问题,如何解决内存泄漏问题?
https://blog.csdn.net/weter_drop/article/details/89387564

1.介绍

内存泄露是指不再使用的对象由于仍然被其他对象引用,导致垃圾收集器(GC)不能及时释放这些对象占用的内存从而造成内存空间浪费的现象。

2.常见场景

2.1 未正确释放资源

数据库、网络、输入输出流,这些资源没有显示的关闭。
垃圾回收只负责内存回收,如果对象正在使用资源的话,Java虚拟机不能判断这些对象是不是正在进行操作,比如输入输出,也就不能回收这些对象占用的内存,所以在资源使用完后要调用close()方法关闭。

2.2 单例模式

单例模式只允许应用程序存在一个实例对象,并且这个实例对象的生命周期和应用程序的生命周期一样长,如果单例对象中拥有另一个对象的引用的话,这个被引用的对象就不能被及时回收。解决办法是单例对象中持有的其他对象使用弱引用,弱引用对象在GC线程工作时,其占用的内存会被回收掉,如下示例:

  1. public class SingleTon1 {
  2. private static final SingleTon1 mInstance = null;
  3. private WeakReference<Context> mContext;
  4. private SingleTon1(WeakReference<Context> context) {
  5. mContext = context;
  6. }
  7. public static SingleTon1 getInstance(WeakReference<Context> context) {
  8. if (mInstance == null) {
  9. synchronized (SingleTon1.class) {
  10. if (mInstance == null) {
  11. mInstance = new SingleTon1(context);
  12. }
  13. }
  14. }
  15. return mInstance;
  16. }
  17. }
  18. public class MyActivity extents Activity {
  19. public void onCreate (Bundle savedInstanceState){
  20. super.onCreate(savedInstanceState);
  21. setContentView(R.layout.main);
  22. SingleTon1 singleTon1 = SingleTon1.getInstance(new WeakReference<Context>(this));
  23. }
  24. }

2.3 慎用静态成员变量

例如:静态的集合类
静态的集合类的生命周期和应用程序的生命周期一样长,所以在程序结束前容器中的对象不能被释放,会造成内存泄露。解决办法是最好不使用静态的集合类,如果使用的话,在不需要容器时要将其赋值为null。

2.4 程序员自己写的工具有问题

2.4.1 自定义的stack【有问题】
  1. import java.util.Arrays;
  2. import java.util.EmptyStackException;
  3. public class MyStack<T> {
  4. private T[] elements;
  5. private int size = 0;
  6. private static final int INIT_CAPACITY = 16;
  7. public MyStack() {
  8. elements = (T[]) new Object[INIT_CAPACITY];
  9. }
  10. public void push(T elem) {
  11. ensureCapacity();
  12. elements[size++] = elem;
  13. }
  14. public T pop() {
  15. if(size == 0)
  16. throw new EmptyStackException();
  17. return elements[--size];
  18. }
  19. private void ensureCapacity() {
  20. if(elements.length == size) {
  21. elements = Arrays.copyOf(elements, 2 * size + 1);
  22. }
  23. }
  24. }

当调用pop的时候,只是—size,数组中还有过期的对象,所以不会被gc回收。

2.4.2 JDK中的stack【没问题】

JDK中Statck底层用的是Vector。
Stack.java

  1. public synchronized E pop() {
  2. E obj;
  3. int len = size();
  4. obj = peek();
  5. removeElementAt(len - 1);
  6. return obj;
  7. }

Vector.java

  1. public synchronized void removeElementAt(int index) {
  2. modCount++;
  3. if (index >= elementCount) {
  4. throw new ArrayIndexOutOfBoundsException(index + " >= " +
  5. elementCount);
  6. }
  7. else if (index < 0) {
  8. throw new ArrayIndexOutOfBoundsException(index);
  9. }
  10. int j = elementCount - index - 1;
  11. if (j > 0) {
  12. System.arraycopy(elementData, index + 1, elementData, index, j);
  13. }
  14. elementCount--;
  15. elementData[elementCount] = null; /* to let gc do its work */
  16. }

看看人家写的,真棒:elementData[elementCount] = null; / to let gc do its work /