JVM之强软弱虚引用

简介: 在Java虚拟机(JVM)中,有几种不同类型的引用,它们分别是:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)和引用队列(Reference Queue)。这些引用类型提供了对对象的不同级别的引用,用于垃圾回收和内存管理。

1. 强引用(Strong Reference)


强引用是最常见的引用类型,它在程序中通过普通的对象引用方式进行声明。当一个对象具有强引用时,垃圾回收器不会回收该对象,即使内存不足也不会被回收。


示例代码:

Object obj = new Object(); // 创建一个强引用对象

我们平常一般使用的引用就是强引用。


2. 软引用(Soft Reference)


软引用是一种比强引用弱一些的引用。当内存不足时,垃圾回收器可能会回收具有软引用的对象,以释放内存。这使得软引用非常适合用于实现内存敏感的高速缓存。


代码示例:

public class a {
    public static void main(String[] args) throws InterruptedException {
        List<SoftReference<byte[]>> list=new ArrayList<>();
        for(int i=0;i<5;i++){
            SoftReference<byte[]> softReference=new SoftReference<>(new byte[4*1024*1024]);
            list.add(softReference);
        }
        for (SoftReference<byte[]> softReference : list) {
            System.out.println(softReference.get());
        }
    }
}


然后在vm options设置堆内存最大内存和打印垃圾回收信息参数如下:

-Xmx20m -XX:+PrintGCDetails -verbose:gc


打印日志如下:

[GC (Allocation Failure) [PSYoungGen: 2287K->488K(6144K)] 14575K->13060K(19968K), 0.0132177 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]

[GC (Allocation Failure) --[PSYoungGen: 4584K->4584K(6144K)] 17156K->17212K(19968K), 0.0010759 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]

[Full GC (Ergonomics) [PSYoungGen: 4584K->4512K(6144K)] [ParOldGen: 12628K->12559K(13824K)] 17212K->17071K(19968K), [Metaspace: 3053K->3053K(1056768K)], 0.0043431 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]

[GC (Allocation Failure) --[PSYoungGen: 4512K->4512K(6144K)] 17071K->17145K(19968K), 0.0008326 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

[Full GC (Allocation Failure) [PSYoungGen: 4512K->0K(6144K)] [ParOldGen: 12633K->672K(8704K)] 17145K->672K(14848K), [Metaspace: 3053K->3053K(1056768K)], 0.0036381 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

null

null

null

null

[B@ed17bee

Heap

PSYoungGen      total 6144K, used 4378K [0x00000000ff980000, 0x0000000100000000, 0x0000000100000000)

 eden space 5632K, 77% used [0x00000000ff980000,0x00000000ffdc6828,0x00000000fff00000)

 from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)

 to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)

ParOldGen       total 8704K, used 672K [0x00000000fec00000, 0x00000000ff480000, 0x00000000ff980000)

 object space 8704K, 7% used [0x00000000fec00000,0x00000000feca8218,0x00000000ff480000)

Metaspace       used 3062K, capacity 4486K, committed 4864K, reserved 1056768K

 class space    used 324K, capacity 386K, committed 512K, reserved 1048576K

Disconnected from the target VM, address: '127.0.0.1:63645', transport: 'socket'

当堆内存不足时,进行垃圾回收的时候,软引用对象就可以被垃圾回收。


3. 引用队列(Reference Queue)


引用队列是一个专门用于管理被垃圾回收器回收的引用对象的队列。当一个对象被回收时,与之关联的引用会被放入引用队列中,以便程序可以检测到对象的回收并执行相应的操作。


public class a {
    public static void main(String[] args) throws InterruptedException {
        List<SoftReference<byte[]>> list=new ArrayList<>();
        ReferenceQueue<byte[]> referenceQueue=new ReferenceQueue<>();
        for(int i=0;i<5;i++){
            SoftReference<byte[]> softReference=new SoftReference<>(new byte[4*1024*1024],referenceQueue);
            list.add(softReference);
        }
        Reference<? extends byte[]> poll = referenceQueue.poll();
        while (poll!=null){
            list.remove(poll);
            poll = referenceQueue.poll();
        }
        for (SoftReference<byte[]> softReference : list) {
            System.out.println(softReference.get());
        }
    }
}

使用引用队列后,就可以删除list集合中的为null的引用。打印日志不再出现null。


4. 弱引用(Weak Reference)


弱引用比软引用更弱一些。弱引用的对象在下一次垃圾回收时几乎肯定会被回收,无论内存是否足够。弱引用通常用于实现对象的临时引用,例如对象的临时计算结果缓存。


代码如下:

public class a {
    public static void main(String[] args) throws InterruptedException {
        List<WeakReference<byte[]>> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            WeakReference<byte[]> weakReference = new WeakReference<>(new byte[4 * 1024 * 1024]);
            list.add(weakReference);
            for (WeakReference<byte[]> reference : list) {
                System.out.print(reference.get()+" ");
            }
            System.out.println();
        }
        list.forEach(i-> System.out.println(i.get()));
    }
}



打印日志如下:

[B@5caf905d

[B@5caf905d [B@27716f4

[B@5caf905d [B@27716f4 [B@8efb846

[GC (Allocation Failure) [PSYoungGen: 2477K->496K(6144K)] 14765K->13219K(19968K), 0.0008677 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

[B@5caf905d [B@27716f4 [B@8efb846 [B@2a84aee7

[GC (Allocation Failure) [PSYoungGen: 4704K->480K(6144K)] 17428K->13227K(19968K), 0.0006313 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

[B@5caf905d [B@27716f4 [B@8efb846 null [B@a09ee92

[B@5caf905d [B@27716f4 [B@8efb846 null [B@a09ee92 Heap

PSYoungGen      total 6144K, used 4745K [0x00000000ff980000, 0x0000000100000000, 0x0000000100000000)

 eden space 5632K, 75% used [0x00000000ff980000,0x00000000ffdaa478,0x00000000fff00000)

 from space 512K, 93% used [0x00000000fff80000,0x00000000ffff8020,0x0000000100000000)

 to   space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)

ParOldGen       total 13824K, used 12747K [0x00000000fec00000, 0x00000000ff980000, 0x00000000ff980000)

 object space 13824K, 92% used [0x00000000fec00000,0x00000000ff872fa8,0x00000000ff980000)

Metaspace       used 3352K, capacity 4500K, committed 4864K, reserved 1056768K

 class space    used 366K, capacity 388K, committed 512K, reserved 1048576K


Process finished with exit code 0


在运行过程中每次打印信息不一样,如果中间发生一次Full GC,那么前面的list集合中的软引用对象全为null。


5. 虚引用(Phantom Reference)


虚引用是最弱的引用类型,它不会阻止对象被垃圾回收。虚引用的主要作用是允许您在对象被回收时收到通知。通常与引用队列(Reference Queue)一起使用,可以在对象被回收时执行一些清理或其他操作。

相关文章
|
缓存 安全 Java
|
安全 Java
JVM11_System.gc、内存溢出、内存泄漏、STW、安全点、安全区域、强软弱虚引用(三)
⑤. 多线程中的并行与并发 ⑥. 垃圾回收的并行、串行、并发
140 0
JVM11_System.gc、内存溢出、内存泄漏、STW、安全点、安全区域、强软弱虚引用(三)
|
缓存 安全 Java
|
1月前
|
存储 安全 Java
jvm 锁的 膨胀过程?锁内存怎么变化的
【10月更文挑战第3天】在Java虚拟机(JVM)中,`synchronized`关键字用于实现同步,确保多个线程在访问共享资源时的一致性和线程安全。JVM对`synchronized`进行了优化,以适应不同的竞争场景,这种优化主要体现在锁的膨胀过程,即从偏向锁到轻量级锁,再到重量级锁的转变。下面我们将详细介绍这一过程以及锁在内存中的变化。
37 4
|
8天前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。
|
5天前
|
Java Linux Windows
JVM内存
首先JVM内存限制于实际的最大物理内存,假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制。
8 1
|
1月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
63 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS