java的内存回收(1)

本文主要探讨了Java的内存回收,强调了开发人员在内存管理中的责任。Java的内存分配与回收由JVM自动完成,但开发人员需关注无用对象的释放。JVM的垃圾回收机制主要针对堆内存中的对象,而栈内存由其他机制回收。文章介绍了JVM通过有向图管理内存对象,并讨论了不同类型的引用对垃圾回收的影响,包括强引用、软引用、弱引用和虚引用。此外,还提到了分代垃圾回收策略,如Young、Old和Permanent代,并提供了开发者管理内存的建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

如果无用的堆内存中的对象在对内存中累计多了的话,等到大批用户一上来,系统的内存就会越来越小,系统响应速度自然变慢

因为java虽然有内存回收机制,但是我们作为开发人员也要显示的管理无用对象的释放,否则系统响应极慢,所以我们应注重内存回收,也要注重内存的分配,这样才能很好的利用有限的内存

使用new去申请分配空间,一个对象失去引用时方可回收

内存的分配与回收都是jvm自动完成的,

jvm的垃圾回收机制负责回收堆内存中除字符串池之外的对象,栈内存由别的机制回收内存,

JDK 1.6之前的常量池实际就是在方法区,JDK 1.7及以后移动到堆中了

new/反序列化/克隆均会申请分配内存

简单来讲,在内存回收方面jvm已经帮我们回收了不可达的无用对象,我们程序需要手动回收的是可达的无用对象,还需要回收字符串池中没有引用指向的字符串对象(解决java的内存泄漏,将引用指针赋值为null),内存中只存在的是可达的有用对象

我们从如下几个方面考虑内存回收

1jvm在核实决定回收一个java对象所占据的内存(对象处于不可达状态)

2jvm会不会漏掉回收某些java对象,使之造成内存泄漏(强引用所指向的系统再也用不到的对象不会被回收)

3jvm回收java对象所占用内存的实现细节(有向图管理,判断是否还有引用)

4jvm能否对不同java对象占用的内存区分对待,回收

5常见垃圾回收机制的实现细节是什么样的?(有向图管理)

1jvm回收java对象所占用内存的方法(一)实现细节(有向图管理,判断是否还有引用

jvm的垃圾回收机制采用有向图方式管理内存中的对象,将线程对象作为有向图的起始顶点,把引用变量和对象作为有向图的顶点,判断对象是否处于可达状态

对象在堆内存中的三种状态:可达状态/可恢复状态(在回收该对象前,系统调用可恢复对象的finalize方法进行资源清理,可以重新获得引用)/不可达状态(彻底失去引用)

注意:

通过这种方法进行垃圾回收并不是特别彻底,虽然垃圾回收机制会将不存在引用的对象回收了,但是有一些对象本身是无用的了,却还是有引用指向他,这样的无用对象垃圾回收机制是回收不了的,因此此处易发生内存泄漏

内存泄漏:存在无用的内存没有被回收回来,就是内存泄漏

2jvm回收java对象所占用内存的方法(二)实现细节(通过引用变量类型进行回收)

引用变量的分类?

强引用: 系统垃圾回收机制运行时,不管系统内存如何,强引用所指向的对象一定不会被回收

               当一个对象被强引用所引用时,jvm即使在系统内存十分紧张的情况下也是不会回收强引用所指向的java对象,

               因此有些强引用指向的对象就算以后不会用到,系统也不会回收,造成内存泄漏

软引用:系统垃圾回收机制运行时,看系统内存的情况,软引用指向的对象不一定会被回收

               系统内存不足时,系统会回收,系统内存足够时,不会被回收

弱引用:系统垃圾回收机制运行时,不管系统内存如何,弱引用所指向的对象一定会被回收

虚引用:跟踪对象被垃圾回收的状态,虚引用必须和引用队列联合使用

对于软引用,弱引用,虚引用,java提供le3个类SoftReference WeakReference  PhantomReference

SoftReference源码

public class SoftReference<T> extends Reference<T> {
static private long clock;
private long timestamp;
public SoftReference(T referent) {
    super(referent);
    this.timestamp = clock;
}
public SoftReference(T referent, ReferenceQueue<? super T> q) {
    super(referent, q);
    this.timestamp = clock;
}
   public T get() {
        T o = super.get();
        if (o != null && this.timestamp != clock)
            this.timestamp = clock;
        return o;
    }

}

WeakReference源码

public class WeakReference<T> extends Reference<T> {
public WeakReference(T referent) {
    super(referent);
}
public WeakReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

}

PhantomReference源码

public class PhantomReference<T> extends Reference<T> {
public T get() {
    return null;
}
 public PhantomReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

}
引用队列 ReferenceQueue
public class ReferenceQueue<T> {
public ReferenceQueue() { }

    private static class Null<S> extends ReferenceQueue<S> {
        boolean enqueue(Reference<? extends S> r) {
            return false;
        }
    }

    static ReferenceQueue<Object> NULL = new Null<>();
    static ReferenceQueue<Object> ENQUEUED = new Null<>();

    static private class Lock { };
    private Lock lock = new Lock();
    private volatile Reference<? extends T> head = null;
    private long queueLength = 0;

    boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
        synchronized (lock) {
            // Check that since getting the lock this reference hasn't already been
            // enqueued (and even then removed)
            ReferenceQueue<?> queue = r.queue;
            if ((queue == NULL) || (queue == ENQUEUED)) {
                return false;
            }
            assert queue == this;
            r.queue = ENQUEUED;
            r.next = (head == null) ? r : head;
            head = r;
            queueLength++;
            if (r instanceof FinalReference) {
                sun.misc.VM.addFinalRefCount(1);
            }
            lock.notifyAll();
            return true;
        }
    }

    @SuppressWarnings("unchecked")
    private Reference<? extends T> reallyPoll() {       /* Must hold lock */
        Reference<? extends T> r = head;
        if (r != null) {
            head = (r.next == r) ?
                null :
                r.next; // Unchecked due to the next field having a raw type in Reference
            r.queue = NULL;
            r.next = r;
            queueLength--;
            if (r instanceof FinalReference) {
                sun.misc.VM.addFinalRefCount(-1);
            }
            return r;
        }
        return null;
    }

    public Reference<? extends T> poll() {
        if (head == null)
            return null;
        synchronized (lock) {
            return reallyPoll();
        }
    }

    
    public Reference<? extends T> remove(long timeout)
        throws IllegalArgumentException, InterruptedException
    {
        if (timeout < 0) {
            throw new IllegalArgumentException("Negative timeout value");
        }
        synchronized (lock) {
            Reference<? extends T> r = reallyPoll();
            if (r != null) return r;
            long start = (timeout == 0) ? 0 : System.nanoTime();
            for (;;) {
                lock.wait(timeout);
                r = reallyPoll();
                if (r != null) return r;
                if (timeout != 0) {
                    long end = System.nanoTime();
                    timeout -= (end - start) / 1000_000;
                    if (timeout <= 0) return null;
                    start = end;
                }
            }
        }
    }

   
    public Reference<? extends T> remove() throws InterruptedException {
        return remove(0);
    }

}j

jvm如何帮我们回收了不可达的无用对象?采用了什么垃圾回收算法?

现行的垃圾回收器采用分代的方式来采用不同的回收设计,

分代的基本思想是根据对象的生存的时间的长短把堆内存分为三代:Young/Old/Permanent

young代的内存会先被回收,而且使用专门的回收算法(复制算法)来回收young代的内存,

对于old代的回收频率则要低得多,也会采用专门的回收算法

开发者管理内存的技巧?----减少内存的分配,减小java的内存泄漏---帮助垃圾回收器回收

1尽早释放无用对象的引用,让垃圾回收机制回收可达的无用对象

2尽量使用直接量,减少对象的创建,多使用字符串缓存池String/Byte/Integer/Short/Chrracter/Double/Float/Boolean

减少不必要的内存浪费String a=“xx"√   Stirng a=new String("xx")×,减少了堆内存对象的产生,减少内存分配,但是如果a在指向其他的字符串对象,也会存在内存泄漏的现象,即xx存在在字符串池中,不会被垃圾回收

3进行字符串拼接时,尽量选用StringBuilder/StringBuffer,减少临时对象,减少内存的分配

4缓存经常使用的对象,数据库连接池,(用空间换时间),减少内存的分配

5避免在经常调用的方法,循环中创建java对象,减少内存的分配

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值