Java知识点小结3:内存回收

文章目录

  • 对象引用
    • 强引用
    • 软引用(SoftReference)
    • 弱引用(WeakReference)
      • 考一考
    • 虚引用(PhantomReference)
    • 总结
  • 垃圾回收
    • 新生代
    • 老年代
    • 永生代
  • 内存管理小技巧
    • 尽量使用直接量
    • 使用StringBuilder和StringBuffer进行字符串拼接
    • 尽早释放无用对象的引用
    • 尽量少用静态变量
    • 避免在循环中创建对象
    • 缓存经常使用的对象
    • 避免使用finalize()方法
    • 使用SoftReference

注:本文是对《疯狂Java面试讲义》的小结。

在这里插入图片描述

对象引用

Java通过 new 关键字来创建对象实例,JVM会在堆内存中为对象分配空间。当对象失去引用时,JVM的垃圾回收机制会自动清理对象,回收内存空间。

可以把对象的引用关系理解为有向图。如果某个对象在图中处于不可达状态,则认为该对象不再被引用。

Java的对象引用方式有:

  • 强引用
  • 软引用
  • 弱引用
  • 虚引用

下面举例说明各种引用方式。

准备:已知类 Person 定义如下:

public class Person {private String name;private int age;......
}

强引用

强引用是最普通、最常见的引用方式。

        Person person = new Person("Tom", 20);

强引用的对象,一定不会被JVM回收。

对于强引用,当内存占用过多时,就会出现 OutOfMemoryError

        Person[] arr1 = new Person[80000];for (int i = 0; i < arr1.length; i++) {arr1[i] = new Person("Tom" + i, i % 20);System.out.println(arr1[i]);}

正常情况下运行结果OK。为了模拟内存被占满的情况,我们把JVM的内存设置为较低值:

-Xmx8m -Xms8m

如果是在命令行下运行:

java -Xmx8m -Xms8m xxxxxx

如果是IntelliJ IDEA,右键,More Run/Debug -> Modify Run Configuration…:

在这里插入图片描述

在弹出的对话框里,点击“Modify options”,在子菜单中确保勾选了“Add VM options”,然后填入 -Xmx8m -Xms8m

在这里插入图片描述

运行结果如下:

......
Person{name='Tom61694', age=14}
Person{name='Tom61695', age=15}
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.base/jdk.internal.misc.Unsafe.allocateUninitializedArray(Unsafe.java:1375)at java.base/java.lang.StringConcatHelper.newArray(StringConcatHelper.java:494)
......

可见,在创建到大约60000个对象的时候,内存就会溢出。

软引用(SoftReference)

软引用的作用是,当内存空间充足时,它不会被系统回收,但是当内存空间不足时,它就会被系统回收。

软引用的用法如下:

        SoftReference<Person> person = new SoftReference<>(new Person("Tom", 20));......person.get();

把上面强引用的代码稍作修改,如下:

        SoftReference<Person>[] arr1 = new SoftReference[80000];for (int i = 0; i < arr1.length; i++) {arr1[i] = new SoftReference<>(new Person("Tom" + i, i % 20));System.out.println(arr1[i].get());}System.out.println(arr1[1].get());System.out.println(arr1[3].get());System.out.println(arr1[79999].get());

运行结果如下(别忘了设置JVM内存):

......
Person{name='Tom79998', age=18}
Person{name='Tom79999', age=19}
null
null
Person{name='Tom79999', age=19}

可见,80000个对象依次创建成功,内存没有溢出,但是创建完毕后,再访问这些对象时,发现前面一部分对象已经变成null了。这是由于在创建后面的对象时,内存不够,触发了垃圾回收,前面的软引用对象被清除了。

多次运行代码,最后一行,有时也会打印出 null ,这说明每次垃圾回收的时机和回收的对象数量是不一定的。

弱引用(WeakReference)

弱引用和软引用类似,区别在于,不管内存是否充足,只要有垃圾回收,弱引用对象就会被回收。

弱引用的用法如下:

        WeakReference<Person> person = new WeakReference<>(new Person("Tom", 20));System.out.println(person.get());System.gc();System.runFinalization();System.out.println(person.get());

运行结果如下(无需设置JVM内存):

Person{name='Tom', age=20}
null

可见,垃圾回收时,弱引用对象被回收了。

WeakReference 功能类似的还有 WeakHashMap

对于map里的key值,如果其对象是弱引用,则在垃圾回收时,会把该对象回收,并把该key值从map里移除。

        WeakHashMap<Person, String> map = new WeakHashMap<>();map.put(new Person("Tom", 20), "aaa");map.put(new Person("Jerry", 30), "bbb");System.out.println(map);System.gc();System.runFinalization();System.out.println(map);

运行结果如下:

{Person{name='Jerry', age=30}=bbb, Person{name='Tom', age=20}=aaa}
{}

考一考

下面的代码,运行结果是什么?

        WeakHashMap<Person, String> map = new WeakHashMap<>();Person person1 = new Person("Tom", 20);map.put(person1, "aaa");// person1 = null;Person person2 = new Person("Jerry", 30);map.put(person2, "bbb");// person2 = null;System.out.println(map);System.gc();System.runFinalization();System.out.println(map);

乍一看,似乎跟前一个例子没什么太大区别,但运行结果是不同的:

{Person{name='Jerry', age=30}=bbb, Person{name='Tom', age=20}=aaa}
{Person{name='Jerry', age=30}=bbb, Person{name='Tom', age=20}=aaa}

这两个key对象为什么没有被回收掉呢?其实原因很简单,因为person1和person2还在引用它们。这是强引用,所以不会被垃圾回收。要想被垃圾回收,只需解除强引用(参见被注释掉的那两行代码)。

虚引用(PhantomReference)

虚引用的主要作用是跟踪对象被垃圾回收的状态。

虚引用不能单独使用,必须和引用队列(ReferenceQueue)一起使用。引用队列保存了被回收后对象的引用。它和软引用、弱引用等联合使用,这些对象被回收时,会把引用添加到相关联的引用队列中。

        ReferenceQueue<Person> queue = new ReferenceQueue<>();PhantomReference<Person> phantomReference = new PhantomReference<>(new Person("Tom", 20), queue);// 虚引用的 get() 方法总是返回nullSystem.out.println(phantomReference.get());// 还没做垃圾回收,所以队列为空System.out.println(queue.poll());System.gc();System.runFinalization();// 垃圾回收后,虚引用对象在队列中System.out.println(queue.poll());

运行结果如下:

null
null
java.lang.ref.PhantomReference@36baf30c

既然虚引用都get不到实际对象,那它到底有什么用呢?

看起来,虚引用的用处,就是会触发一个事件。我们可以另起一个线程,对队列进行监听,比如:

  • remove() :阻塞方法
  • poll() :非阻塞方法

这样,当对象被回收时,我们就会得到通知,做相应的处理(比如清理资源)。

总结

强引用软引用弱引用
垃圾回收时,不会被回收YNN
垃圾回收时,若内存不足,就会被回收NYY
只要有垃圾回收,就会被回收NNY

垃圾回收

垃圾回收机制主要做两件事:

  • 跟踪每个Java对象的可达状态,回收不可达对象的内存
  • 清理分配和回收过程中产生的内存碎片

垃圾回收的设计思想:

  • 串行和并行:使用单CPU还是多CPU来做回收
  • 并发和停止(stop-the-world):回收时,应用是否暂停
  • 紧凑和不紧凑:如果只是回收对象,则内存可能会产生很多碎片。把所有活着的对象复制到一起,可以避免内存碎片

回收方式:

  • 复制:把内存分成两个相同的空间A和B,以A空间为例,从根开始,把每个可达对象复制到B空间,最后把整个A空间重置
  • 标记清除(mark-sweep):从根开始,标记每个可达对象,最后回收所有没有标记可达的对象
  • 标记清除紧凑(mark-sweep-compact):从根开始,标记每个可达对象,最后把所有活着的对象搬迁在一起,并回收其它内存空间

分代内存:

  • 新生代(Young):大部分对象存活时间不会很长,处于新生代
  • 老年代(Old):少量对象存活时间很长,处于老年代
  • 永生代(Permanent):主要用于存放Class对象,方法等信息

新生代

新生代又分为Eden(伊甸园)区和Survivor区。

绝大部分对象先分配到Eden区,而Survivor区的对象至少熬过一次垃圾回收。

Survivor区又分为From区和To区,参见上面提到的“复制”回收方式。

垃圾回收时,将Eden区和From区的可达对象复制到To区,然后清空Eden区和From区,最后把From和To互换一下。

老年代

如果一个对象熬过了数次垃圾回收,就可能会被转入老年代。

老年代的垃圾回收频率无需太高,因为老年代的对象都很能熬。

  • 次要回收:新生代的垃圾回收,频率较高
  • 主要回收:新生代和老年代的垃圾回收,频率较低

老年代的垃圾回收通常采用标记清除紧凑算法。

永生代

主要用于存放Class对象,方法等信息,默认为64MB。

内存管理小技巧

尽量使用直接量

        String str1 = "hello"; // 在字符串缓存池里缓存了hello字符串String str2 = new String("hello"); //同上,此外还多创建了一个char[]数组

使用StringBuilder和StringBuffer进行字符串拼接

String字符串是不可变的,如果直接对字符串拼接,将产生大量的临时字符串。

        String str1 = "hello";String str2 = "world";String str3 = "!!!";String result1 = str1 + str2 + str3; // 产生大量的临时字符串System.out.println(result1);StringBuilder result2 = new StringBuilder();result2.append(str1);result2.append(str2);result2.append(str3);System.out.println(result2.toString());StringBuffer result3 = new StringBuffer();result3.append(str1);result3.append(str2);result3.append(str3);System.out.println(result3.toString());

尽早释放无用对象的引用

        Person person = new Person("Tom", 20);person.doSomething();// person = null;......

本例中,创建并使用完person对象后,最好将其释放(参见注释处代码),否则,person变量在其作用域范围内,会一直持有对象引用,导致对象无法被系统回收。

尽量少用静态变量

class A {static B b = new B();
}

本例中,b是A类的静态变量,其生命周期与A类一致(存入永生代)。

避免在循环中创建对象

        for (int i = 0; i < 100; i++) {Person person = new Person("Tom", 20);......}

创建了100个Person对象,它们的生存时间都很短。系统需要不断的分配和回收内存。

缓存经常使用的对象

典型的例子是数据库连接池。

避免使用finalize()方法

垃圾回收的工作量已经很大了,尤其是新生代,对象很多,回收频繁,若再使用finalize()方法清理资源,更加重了垃圾回收的负担。

使用SoftReference

参见前面的介绍。

注意SoftReference和WeakReference的不确定性,在使用对象时,应检查其是否为空。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/145143.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【我的 PWN 学习手札】Tcache dup

前言 Tcache dup&#xff0c;实际上是 tcache 的 double free&#xff0c;能达到 UAF 的效果&#xff0c;实现 Tcache poisoning。 一、Tcache dup 早期 tcache 没有检查 double free&#xff0c;也没有对 counts 做检查。 对同一个大小落在 Tcachebin 的 chunk 进行 doubl…

鸿蒙媒体开发系列07——AVRecorder音频录制

如果你也对鸿蒙开发感兴趣&#xff0c;加入“Harmony自习室”吧&#xff01;扫描下方名片&#xff0c;关注公众号&#xff0c;公众号更新更快&#xff0c;同时也有更多学习资料和技术讨论群。 1、概述 在HarmonyOS系统中&#xff0c;多种API都提供了音频录制开发的支持&#x…

Stable Diffusion 使用详解(11)--- 场景ICON制作

目录 背景 controlNet 整体描述 Canny Lineart Depth 实际使用 AI绘制需求 绘制过程 PS打底 场景模型选择 设置提示词及绘制参数 controlnet 设置 canny 边缘 depth 深度 lineart 线稿 效果 背景 这段时间不知道为啥小伙伴似乎喜欢制作很符合自己场景的ICON。…

Codeforces Round 784 (Div. 4) Kotlin

本期封面原图 画师煮タ 大福豆 最近学了下Kotlin的基础语法 想着巩固一下就开了一把div4 最后几题没时间了还是换回了C 要不然没法AK了 Idea编译的时候最后必须加上一句main函数的调用&#xff0c;但是cf的测评机又不能加这一句&#xff0c;总是忘记注释掉所以ce了很多发&…

Leetcode Hot 100刷题记录 -Day18(反转链表)

反转链表&#xff1a; 问题描述&#xff1a; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&a…

工作中遇到的问题总结(1)

文章目录 第一题问题描述解决思路 第二题问题描述解决思路核心大表如何优化数据迁移过程是怎么样的如何将流量从旧系统迁移到新系统上 第三题问题描述解决思路 第四题问题描述解决思路方案一&#xff1a;双写机制方案二&#xff1a;基于时间戳的分流机制方案三&#xff1a;灰度…

【资料分析】刷题日记3

第一套 √ 考点&#xff1a;基期比重差很温柔的题 普通专科女生 占比 52.5% - 1.7% 50.8% 成人本专科女生 占比 57.8% - 4.6% 53.2% 相比降低了2.4% 知比重和部分量&#xff0c;求整体在花生老师的解法中体会啥叫适当约分 0.1899 / 47.8% / 87.5% 》0.19 / &#xff08;4…

MySQL高阶1890-2020年最后一次登录

目录 题目 准备数据 分析数据 题目 编写解决方案以获取在 2020 年登录过的所有用户的本年度 最后一次 登录时间。结果集 不 包含 2020 年没有登录过的用户。 返回的结果集可以按 任意顺序 排列。 准备数据 Create table If Not Exists Logins (user_id int, time_stamp …

Ansbile-变量

文章目录 一、Ansible的常量&#xff08;内置的变量&#xff09;有哪些&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1…

Java之封装

文章目录 1.封装1.1 什么是封装1.2 访问限定符1.3 包1.3.1 什么是包1.3.2 导包1.3.3 自定义包 2. static2.1 static 修饰成员变量2.2 static 修饰成员方法2.3 static成员变量初始化 3. 代码快3.1 普通代码块3.2 实例代码块3.3 静态代码块 4. 对象的打印 1.封装 1.1 什么是封装…

力扣 713.乘积小于k的子数组

文章目录 题目介绍解法 题目介绍 解法 和209.长度最小的子数组思路大致相同。 思路&#xff1a;如果从l到r这一段的乘积是小于k的&#xff0c;那么[l,r]、[l1,r]….[r,r]这些子数组都是满足乘积小于k的&#xff0c;一共有r-l1个。 class Solution {public int minSubArrayLen…

Node.js backend for OpenAI image generation giving error code 400

题意&#xff1a;用于 OpenAI 图像生成的 Node.js 后端返回错误代码 400。 问题背景&#xff1a; I am trying to build a backend for the first time using Node.js. This is what I need: Generate image based on prompt -> Get the image and upload it to supabase s…

浅析OceanBase数据库的向量化执行引擎

本篇博客是偏数据库系统概念性的内容&#xff0c;不会深入到 OceanBase 中各个算子和表达式的在向量化中的详细设计和实现。 背景 为了提升OceanBase社区版用户解决问题的效率&#xff0c;OceanBase官方不久前推出了《OceanBase 从入门到实践》系列课程。在第七期直播课程后&a…

基于MATLAB的安全帽检测系统

课题名称 课题介绍 众所周知&#xff0c;在一些施工工地&#xff0c;必须明确佩戴安全帽。可以对生命安全起到保障作用。该课题为常见的安全帽的识别&#xff0c;主要分为红色&#xff0c;蓝色&#xff0c;黄色三类安全帽。而安全帽的主要是红色&#xff0c;蓝色&…

项目文件配置

1. 参数配置化 1.1 问题分析 1.2 问题解决 Value 注解通常用于外部配置的属性注入&#xff0c;具体用法为&#xff1a;Value("${配置文件中的key}") 2. yml配置文件 2.1 SpringBoot提供了多种属性配置方式 2.2 常见配置文件格式对比 2.3 yml 基本语法 大小写敏…

相位型SLM硬件产品面型性能提升

背景介绍 作为一种动态可编程光学元件&#xff0c;液晶空间光调制器&#xff08;LC-SLM&#xff09;在波前整形和光束控制等精密光学调控应用中发挥着非常重要的作用。典型的纯相位SLM工作原理是通过加载的电压控制在每个液晶像素处诱导相位延迟&#xff0c;实现对入射光波波前…

滚珠花键与滚珠丝杆的区别与应用

在机械工业中&#xff0c;经常使用滚珠花键这种传动元件&#xff0c;人们经常拿它与滚珠丝杆相比较&#xff0c;甚至与之混淆。事实上&#xff0c;它们是不同的&#xff0c;滚珠花键和滚珠丝杆在机械传动领域中各有其独特的作用和特点。那么&#xff0c;两者之间的区别是什么呢…

渐变色代码主题你受得了吗

分享一个vscode编辑器的渐变色主题 效果图如下 vscode扩展搜索 gradient theme安装即可。

LinuxC高级作业2

1.整理思维导图 2.做一套笔试题 一&#xff1a; 1.cd .. mkdir dir1 cd dir1 touch file1 2.cp ~/mnt/dir1/ -r * ~/home/dir2/ 3.pwd 4.ls -l 5.ifconfig 6.top 10.find /usr -type f -name "*name*" 11.:wq 13.df -h 14.tar -xzvf tmp.tar.gz 15.sudo c…

Windows安装启动:stable-diffusion-webui,AIGC大模型文生图、文生视频,Python

Windows安装启动:stable-diffusion-webui&#xff0c;AIGC大模型文生图、文生视频&#xff0c;Python stable-diffusion-webui是github上的AIGC开源项目&#xff0c;地址&#xff1a; https://github.com/AUTOMATIC1111/stable-diffusion-webuihttps://github.com/AUTOMATIC1…