JVM11_System.gc、内存溢出、内存泄漏、STW、安全点、安全区域、强软弱虚引用(五)

简介: ⑨. 引用①. 强引用:不回收②. 软引用: 内存不足即回收

⑨. 引用


①. 我们希望能描述这样一类对象: 当内存空间还足够时,则能保留在内存中;如果内存空间在进行垃圾收集后还是很紧张,则可以抛弃这些对象。 -【既偏门又非常高频的面试题】强引用、软引用、弱引用、虚引用有什么区别?具体使用.场景是什么?


②. 在JDK 1.2版之后,Java对引用的概念进行了扩充,将引用分为强引用(Strong

Reference)、软引用(Soft Reference) 、弱引用(Weak Reference) 和虚引用(Phantom Reference) 4种,这4种引用强度依次逐渐减弱


③. 除强引用外,其他3种引用均可以在java.lang.ref包中找到它们的身影。如下图,显示了这3种引用类型对应的类,开发人员可以在应用程序中直接使用它们。


微信图片_20220106155905.png


④. Reference子类中只有终结器引用是包内可见的,其他3种引用类型均为public,可以在应用程序中直接使用


⑤. 简单介绍下强软弱虚引用


强引用(StrongReference)I :最传统的“引用”的定义,是指在程序代码之中普遍存在的引用赋值,即类似“0bject obj=new object( )”这种引用关系。 无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象


软引用(SoftReference) :在系统将要发生内存溢出之前,将会把这些对象列入回收范围之中进行第二次回收。如果这次回收后还没有足够的内存,才会抛出内存溢出异常 内存不足即回收


弱引用(WeakReference) :被弱引用关联的对象只能生存到下一次垃圾收集之前。当垃圾收集器工作时,无论内存空间是否足够,都会回收掉被弱引用关联的对象。 发现即回收


虚引用(PhantomReference) :一个对象是否有虛引用的存在,完全不会对其生存时 间构成影响,也无法通过虚引用来获得一个对象的实例。 为一个对象设置虛引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知(回收跟踪)


微信图片_20220106155937.png


①. 强引用:不回收


在Java程序中,最常见的引用类型是强引用(普通系统99%以上都是强引用),也就是我们最常见的普通对象引用,也是默认的引用类型。


当在Java语言中使用new操作符创建一个新的对象, 并将其赋值给一个变量的时候,这个变量就成为指向该对象的一个强引用。


强引用的对象是可触及的,垃圾收集器就永远不会回收掉被引用的对象。


对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为null,就是可以当做垃圾被收集了,当然具体回收时机还是要看垃圾收集策略。


相对的,软引用、 弱引用和虚引用的对象是软可触及、弱可触及和虛可触及的,在一定条件下,都是可以被回收的。所以,强引用是造成Java内存泄漏的主要原因之一。


②. 软引用: 内存不足即回收


①. 软引用是用来描述一 些还有用,但非必需的对象。只被软引用关联着的对象,在系统将要发生内存溢出异常前,会把这些对象列进回收范围之中进行第二次回收,如果这次回收还没有足够的内存,才会抛出内存溢出异常。

注意:一次回收是回收强引用中没有引用的对象


②. 软引用通常用来实现内存敏感的缓存。比如:高速缓存就有用到软引用。如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存


③. 类似弱引用,只不过Java虚拟机会尽量让软引用的存活时间长一些,迫不得.已才清理


④. 软引用:


  1. 当内存足够: 不会回收软用的可达对象


  1. 当内存不够时: 会回收软引用的可达对象


⑤. 在JDK 1. 2版之后提供了java.lang.ref.SoftReference类来实现软引用。


  Object obj = new object(); //声明强引用
  SoftReference<0bject> sf = new SoftReference<0bject>(obj);
  obj = null; //销毁强引用


⑥. 测试代码


/**
 * 软引用的测试:内存不足即回收
 * -Xms10m -Xmx10m -XX:+PrintGCDetails
 */
public class SoftReferenceTest {
    public static class User {
        public User(int id, String name) {
            this.id = id;
            this.name = name;
        }
        public int id;
        public String name;
        @Override
        public String toString() {
            return "[id=" + id + ", name=" + name + "] ";
        }
    }
    public static void main(String[] args) {
        //创建对象,建立软引用
//        SoftReference<User> userSoftRef = new SoftReference<User>(new User(1, "songhk"));
        //上面的一行代码,等价于如下的三行代码
        User u1 = new User(1,"songhk");
        SoftReference<User> userSoftRef = new SoftReference<User>(u1);
        u1 = null;//取消强引用
        //从软引用中重新获得强引用对象
        System.out.println(userSoftRef.get());
        System.gc();
        System.out.println("After GC:");
//        //垃圾回收之后获得软引用中的对象
        System.out.println(userSoftRef.get());//由于堆空间内存足够,所有不会回收软引用的可达对象。
//
        try {
            //让系统认为内存资源紧张、不够
//            byte[] b = new byte[1024 * 1024 * 7];
            byte[] b = new byte[1024 * 7168 - 399 * 1024];//恰好能放下数组又放不下u1的内存分配大小 不会报OOM
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            //再次从软引用中获取数据
            System.out.println(userSoftRef.get());//在报OOM之前,垃圾回收器会回收软引用的可达对象。
        }
    }
}
相关文章
|
1月前
|
Java Docker 索引
记录一次索引未建立、继而引发一系列的问题、包含索引创建失败、虚拟机中JVM虚拟机内存满的情况
这篇文章记录了作者在分布式微服务项目中遇到的一系列问题,起因是商品服务检索接口测试失败,原因是Elasticsearch索引未找到。文章详细描述了解决过程中遇到的几个关键问题:分词器的安装、Elasticsearch内存溢出的处理,以及最终成功创建`gulimall_product`索引的步骤。作者还分享了使用Postman测试接口的经历,并强调了问题解决过程中遇到的挑战和所花费的时间。
|
20天前
|
安全 Java API
【性能与安全的双重飞跃】JDK 22外部函数与内存API:JNI的继任者,引领Java新潮流!
【9月更文挑战第7天】JDK 22外部函数与内存API的发布,标志着Java在性能与安全性方面实现了双重飞跃。作为JNI的继任者,这一新特性不仅简化了Java与本地代码的交互过程,还提升了程序的性能和安全性。我们有理由相信,在外部函数与内存API的引领下,Java将开启一个全新的编程时代,为开发者们带来更加高效、更加安全的编程体验。让我们共同期待Java在未来的辉煌成就!
46 11
|
22天前
|
安全 Java API
【本地与Java无缝对接】JDK 22外部函数和内存API:JNI终结者,性能与安全双提升!
【9月更文挑战第6天】JDK 22的外部函数和内存API无疑是Java编程语言发展史上的一个重要里程碑。它不仅解决了JNI的诸多局限和挑战,还为Java与本地代码的互操作提供了更加高效、安全和简洁的解决方案。随着FFM API的逐渐成熟和完善,我们有理由相信,Java将在更多领域展现出其强大的生命力和竞争力。让我们共同期待Java编程新纪元的到来!
42 11
|
1月前
|
存储 算法 Oracle
不好意思!耽误你的十分钟,JVM内存布局还给你
先赞后看,南哥助你Java进阶一大半在2006年加州旧金山的JavaOne大会上,一个由顶级Java开发者组成的周年性研讨会,公司突然宣布将开放Java的源代码。于是,下一年顶级项目OpenJDK诞生。Java生态发展被打开了新的大门,Java 7的G1垃圾回收器、Java 8的Lambda表达式和流API…大家好,我是南哥。一个Java学习与进阶的领路人,相信对你通关面试、拿下Offer进入心心念念的公司有所帮助。
不好意思!耽误你的十分钟,JVM内存布局还给你
|
1月前
|
存储 算法 Java
JVM自动内存管理之垃圾收集算法
文章概述了JVM内存管理和垃圾收集的基本概念,提供一个关于JVM内存管理和垃圾收集的基础理解框架。
JVM自动内存管理之垃圾收集算法
|
1月前
|
存储 Java 程序员
JVM自动内存管理之运行时内存区
这篇文章详细解释了JVM运行时数据区的各个组成部分及其作用,有助于理解Java程序运行时的内存布局和管理机制。
JVM自动内存管理之运行时内存区
|
28天前
|
数据采集 Rust 安全
Rust在网络爬虫中的应用与实践:探索内存安全与并发处理的奥秘
【8月更文挑战第31天】网络爬虫是自动化程序,用于从互联网抓取数据。随着互联网的发展,构建高效、安全的爬虫成为热点。Rust语言凭借内存安全和高性能特点,在此领域展现出巨大潜力。本文探讨Rust如何通过所有权、借用及生命周期机制保障内存安全;利用`async/await`模型和`tokio`运行时处理并发请求;借助WebAssembly技术处理动态内容;并使用`reqwest`和`js-sys`库解析CSS和JavaScript,确保代码的安全性和可维护性。未来,Rust将在网络爬虫领域扮演更重要角色。
55 1
|
1月前
|
存储 安全 Java
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程是什么,JDK、JRE、JVM的联系与区别;什么是程序计数器,堆,虚拟机栈,栈内存溢出,堆栈的区别是什么,方法区,直接内存
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存
|
1月前
|
存储 安全 Java
JVM内存结构
这篇文章详细介绍了Java虚拟机(JVM)的内存结构,包括类的加载过程、类加载器的双亲委派机制、沙箱安全机制、程序计数器、Java栈、Java堆、本地方法和本地方法栈等关键组件及其作用。
JVM内存结构
|
28天前
|
Rust 安全 程序员
揭秘Rust语言的内存安全秘籍:如何构建坚不可摧的系统级应用?
【8月更文挑战第31天】Rust语言凭借其独特内存安全机制在编程领域脱颖而出,通过所有权、借用与生命周期等概念,在保证高性能的同时避免了缓冲区溢出等常见错误。本文深入探讨Rust的内存安全机制,并通过示例代码展示如何利用这些机制构建高效且可靠的系统。尽管这些机制增加了学习难度,但为软件开发奠定了坚实基础,使Rust成为系统、嵌入式及网络编程的理想选择。随着社区的发展,Rust将在未来软件开发中扮演更重要角色。
30 0