java 对象引用 弱引用吗_谈谈Java对象的强引用,软引用,弱引用,虚引用分别是什么...

整体结构

java提供了4中引用类型,在垃圾回收的时候,都有自己的各自特点。

72bfef55ce807d5bda36986991b3efc1.png

为什么要区分这么多引用呢,其实这和Java的GC有密切关系。

强引用(默认支持模式)

把一个对象赋给一个引用变量,这个引用变量就是一个强引用。

强引用是我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表明对象还活着

当内存不足的时候,jvm开始垃圾回收,对于强引用的对象,就算出现OOM也不会回收该对象的。

因此,强引用是造成java内存泄露的主要原因之一。

对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显示的将引用赋值为null,GC就会回收这个对象了。

案例

public static void main(String[] args) {

Object obj=new Object();//这样定义就是一个强引用

Object obj2=obj;//也是一个强引用

obj=null;

System.gc();

//不会被垃圾回收

System.out.println(obj2);

}

软引用(SoftReference)

软引用是一种相对强化引用弱化了一些引用,需要使用java.lang.SoftReference类来实现。

对于只有软引用的对象来说,

当系统内存充足时,不会被回收;

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

软引用适合用于缓存,当内存不足的时候把它删除掉,使用的时候再加载进来

案例

/**

* jvm配置配置小的内存,故意产生大的对象,导致OOM,

* 验证软引用在内存足够的前后是否被回收。

* 参数:-Xms:5M -Xmx:5M

* @param args

*/

public static void main(String[] args) {

Object obj=new Object();//这样定义就是一个强引用

//软引用需要使用java.lang.SoftReference来实现

//现在sf就是一个软引用

SoftReference sf=new SoftReference(obj);

obj=null;

System.out.println("内存足够软引用引用的对象"+sf.get());

try {

final byte[] bytes = new byte[8 * 1024 * 1024];

} catch (Exception e) {

e.printStackTrace();

}finally {

System.out.println("内存不够:软引用引用的对象:"+sf.get());

}

}

结果:

768be06973293fd49457f8600507a5db.png

弱引用

弱引用需要用java.lang.WeakReference类来实现,它比软引用的生存期更短。

*如果一个对象只是被弱引用引用者,那么只要发生GC,不管内存空间是否足够,都会回收该对象。

弱引用适合解决某些地方的内存泄漏的问题

ThreadLocal静态内部类ThreadLocalMap中的Entiry中的key就是一个虚引用;

案例

public static void main(String[] args) {

Object obj=new Object();

WeakReference wrf=new WeakReference(obj);

obj=null;

System.out.println("未发生GC之前"+wrf.get());

System.gc();

System.out.println("内存充足,发生GC之后"+wrf.get());

}

结果:

未发生GC之前java.lang.Object@2d363fb3

内存充足,发生GC之后null

ThreadLocal

851ee6fc97f6b5f40422ad2121d31fa1.png

你知道弱引用的话,能谈谈WeakHashMap吗?

WeakHashMap的键是“弱键”,也就是键的引用是一个弱引用。

public static void main(String[] args) {

WeakHashMap map=new WeakHashMap<>();

String key = new String("wekHashMap");

map.put(key,1);

key=null;

System.gc();

System.out.println(map);

}

结果:map为空了。

理论上我们只是把引用变量key变成null了,"wekHashMap"字符串应该被Map中key引用啊,不应该被GC回收啊,

但是因为key是弱引用,GC回收的时候就忽略了这个引用,把对象当成垃圾收回了。

虚引用

虚引用需要 java. langref.PhantomReference类来实现。

顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。

如果一个对象仅被虛引用持有,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

它不能单独使用也不能通过它访问对象,虚引用必须和引用队列( Reference queue)联合使用。

虚引用的主要作用是跟踪对象被垃圾回收的状态。仅仅是提供了一种确保对象被 finalize以后,做某些事情的机制。

PhantomReference的get方法总是返回null,因此无法访问对应的引用对象。

使用它的意义在于说明一个对象已经进入 finalization阶段,可以被回收,用来实现比 finalization机制更灵活的回收操作

换句话说,设置虚引用关联的唯一目的,就是在这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步的处理;

虚引用用来管理堆外内存

34cc1246491a62ec16650a1ed5204315.png

ReferenceQueue 引用队列

对象在被回收之前要被引用队列保存一下。GC之前对象不放在队列中,GC之后才对象放入队列中。

【通过开启线程监听该引用队列的变化情况】就可以在对象被回收时采取相应的动作。

由于虚引用的唯一目的就是能在这个对象被垃圾收集器回收时能收到系统通知,因而创建虚引用时必须要关联一个引用队列,而软引用和弱引用则不是必须的。

这里所谓的收到系统通知其实还是通过开启线程监听该引用队列的变化情况来实现的。

这里还需要强调的是,

对于软引用和弱引用,当执行第一次垃圾回收时,就会将软引用或弱引用对象添加到其关联的引用队列中,然后其finalize函数才会被执行(如果没复写则不会被执行);

而对于虚引用,如果被引用对象没有复写finalize方法,则是在第一垃圾回收将该类销毁之后,才会将虚拟引用对象添加到引用队列,

如果被引用对象复写了finalize方法,则是当执行完第二次垃圾回收之后,才会将虚引用对象添加到其关联的引用队列

一个对象的finalize()方法只会被调用一次,而且finalize()被调用不意味着gc会立即回收该对象,所以有可能调用finalize()后,

该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会调用finalize(),产生问题,所以,推荐不要使用finalize()方法

class User{

@Override

protected void finalize() throws Throwable {

super.finalize();

System.out.println("我要被GC干了!");

}

}

public static void main(String[] args) throws Exception {

User user=new User();

ReferenceQueue queue=new ReferenceQueue();

PhantomReference prf=new PhantomReference(user,queue);

//启动一个线程监控引用队列的变化

new Thread(()->{

for(;;){

final Reference extends User> u = queue.poll();

if (u!=null){

System.out.println("有对象被加入到了引用队列了!"+u);

}

}

}).start();

user=null;

//GC之前引用队列为空

System.out.println("GC之前"+queue.poll());

System.gc();

Thread.sleep(100);

//GC之后引用队列才将对象放入

System.out.println("第一次GC之后"+queue.poll());

System.gc();

Thread.sleep(100);

System.out.println("第二次GC之后"+queue.poll());

}

结果:

GC之前null

我要被GC干了!

第一次GC之后null

有对象被加入到了引用队列了!java.lang.ref.PhantomReference@549763fd

第二次GC之后java.lang.ref.PhantomReference@5aaa6d82

应用场景

软引用:SoftReference的应用场景

假如有一个应用需要读取大量的本地图片

每次读取图片都从硬盘读取会影响性能。

一次全部加载到内存中,又可能造成内存溢出。

此时,可以使用软引用解决问题;

使用一个HashMap保存图片的路径和响应图片对象关联的软引用之间的映射关系,

内存不足时,jvm会自动回收这些缓存图片对象所占用的空间,可以避免OOM。

Map> imageCache=new HashMap>();

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python图像几何变换_Python 图像处理 OpenCV (5):图像的几何变换

前文传送门&#xff1a; 图像缩放 图像缩放只是调整图像的大小&#xff0c;为此&#xff0c; OpenCV 为我们提供了一个函数 cv.resize() &#xff0c;原函数如下&#xff1a; resize(src, dsize, dstNone, fxNone, fyNone, interpolationNone) src 表示的是输入图像&#xff0c…

linux中python编辑器_Linux下9款最好的Markdown编辑器

首先&#xff0c; Markdown是使用Perl编写的&#xff0c;简单、轻量级的工具&#xff0c;允许用户编写纯文本格式和高效的html或者XHTML。它实际上是一个易于阅读&#xff0c;易于编写纯文本的语言和文本到HTML的转换的软件工具。 希望你有一点了解&#xff0c;Mrakdown是什么&…

java监听数据库操作_第十六篇——JDBC操作数据库之监听器

JavaWeb应用中&#xff0c;很多的地方都和session有关。因此session相关的事件监听器&#xff0c;在日常工作中非常有用。有时候我们需要统计当前在线的人数和访问人数总数&#xff0c;此时就可以使用监听器技术来很简单的实现这种功能。注意&#xff1a;session并不是浏览器关…

加装的硬盘进入后点不了文件夹_在外接移动硬盘上制作win to go教程

有很多使用Mac Book的小伙伴免不了要使用一些Windows下才有的软件(强行暗示Solidworks)&#xff0c;这类的大型软件在虚拟机当中运行稳定性又不太好&#xff0c;所以双系统便成了许多人的选择&#xff0c;但boot camp让本就拮据的机身内存雪上加霜&#xff0c;由此win to go便成…

python爬虫动态解析js_Python爬虫实战入门五:获取JS动态内容—爬取今日头条

F12打开网页调试工具&#xff1a;选择“网络”选项卡后&#xff0c;发现有很多响应&#xff0c;我们筛选一下&#xff0c;只看XHR响应。&#xff08;XHR是Ajax中的概念&#xff0c;表示XMLHTTPrequest&#xff09;然后我们发现少了很多链接&#xff0c;随便点开一个看看&#x…

openjdk怎么执行java命令_Ubuntu 18.04 上使用 OpenJDK 安装并运行 Tomcat

在Linux上安装与卸载JDK和JRE&#xff0c;两种常用方法&#xff1a;一、通过 apt-get 命令在线进行安装与卸载(会自动配置好环境变量)二、通过下载并解压 .tar.gz 包进行手动安装与手动卸载(需要手动配置环境变量)注&#xff1a;javac命令是JDK中的&#xff0c;java命令是JRE中…

vscode卸载background插件_萌妹程序员鼓励师24小时在线陪你写代码,给我吹爆这个VSCode插件...

开源最前线(ID&#xff1a;OpenSourceTop) 猿妹综合整理项目地址&#xff1a;https://github.com/SaekiRaku/vscode-rainbow-fart最近&#xff0c;Github上有一个名为Rainbow Fart的VSCode 插件被玩坏了&#xff0c;有了这个插件&#xff0c;程序员鼓励师这个物种就要灭绝了。为…

java 获取td_[Java教程]jQuery获取table表中的td标签

[Java教程]jQuery获取table表中的td标签0 2017-07-28 00:00:08首先我来介绍一下我遇到的问题1.当有一个table表包含了标签&#xff0c;标签&#xff0c;大致可以认为是这样的&#xff1a;scene.ID scene.SceneName scene.QRUrl scene.LocalUrl if (!string.IsNullOrWhiteSpace(…

引用另一模板的宏_生信人值得拥有的编程模板Shell

前言“工欲善其事必先利其器”&#xff0c;生信工程师每天写代码、搭流程&#xff0c;而且要使用至少三门编程语言&#xff0c;没有个好集成开发环境(IDE&#xff0c;Integrated Development Environment)那怎么行&#xff1f;本人使用过vim, editplus, ultraedit, notepad, su…

avlib java_fatal error: libavutil/avconfig.h: No such file...

根据这位仁兄的记录&#xff0c;可以在android程序里调用ffmpeg的avcodec_version()函数&#xff1b;下载了最新版的ffmpeg源码(2.4.1)&#xff0c;在cygwin里用NDK编译时可能会报错&#xff0c;报错如下&#xff1b;your_nameAP-CHN-LP140129 /cygdrive/c/Workspace_my/TestAp…

python 绘制分布直方图_统计学中常见的4种抽样分布及其分布曲线(Python绘制)...

现代统计学奠基人之一、英国统计学家费希尔(Fisher)曾把抽样分布、参书估计和假设检验看作统计推断的三大中心内容。统计学中&#xff0c;需要研究统计量的性质&#xff0c;并评价一个统计推断的优良性&#xff0c;而这些取决于其抽样分布的性质&#xff0c;所以&#xff0c;抽…

php 文件 不更新,php页面不刷新更新数据

php页面不刷新更新数据php页面不刷新更新数据实现起来很简单&#xff0c;我们可以使用前端的ajax技术。ajax作用&#xff1a;ajax技术的目的是让javascript发送http请求&#xff0c;与后台通信&#xff0c;获取数据和信息。实现前后端分离。ajax技术的原理是实例化xmlhttp对象&…

master节点部署pod_小伙!Kubernetes 部署如此简单,你看完全明白了

将项目迁移到k8s平台是怎样实现的?制作镜像控制器管理PodPod数据持久化暴露应用对外发布应用日志/监控1、制作镜像分为三步第一基础镜像&#xff0c;是基于哪个操作系统&#xff0c;比如Centos7或者其他的第二步中间件镜像&#xff0c;比如服务镜像&#xff0c;跑的像nginx服务…

c++从入门到精通_资料下载:从入门到精通,手把手教你学DSP

学习一个东西首先是了解它&#xff0c;比如DSP到底是什么&#xff1f;用在什么地方&#xff1f;怎么用&#xff1f;和单片机特点有那些相同与不同&#xff1f;开发需要注意什么&#xff1f;想了解清楚这些问题自然就清楚比较清楚的认识DSP。DSP&#xff0c;因为它是用来做数据处…

php mysql存中文,PHP+MySQL存储数据常见中文乱码问题小结

PHPMySQL存储数据常见中文乱码问题小结本文实例总结了PHPMySQL存储数据常见中文乱码问题。分享给大家供大家参考&#xff0c;具体如下&#xff1a;PHPMySQL出现中文乱码的常见原因:1. MYSQL数据库的编码是utf8,与PHP网页的编码格式不一致,就会造成MYSQL中的中文乱码。2. 使用MY…

dbf文件怎么创建_ThinkPHP6开发博客实战入门(三),创建admin后台入口

打开创建的应用根目录&#xff1a;E:phpstudy_proWWWp(注意&#xff0c;往后我所说的根目录就是此路径)简单说一下tp6的目录结构app应用目录主要存放控制器文件&#xff1b;config配置目录主要存放全局配置文件&#xff1b;public入口目录主要存放入口或者资源文件&#xff1b;…

没有返回值的方法mock怎么写_【方法】小学生怎么写读书笔记?

什么是读书笔记读书笔记&#xff0c;是指人们在阅读书籍或文章时&#xff0c;遇到值得记录的东西和自己的心得、体会&#xff0c;随时随地把它写下来的一种文体。古人有条著名的读书治学经验&#xff0c;叫做读书要做到&#xff1a;眼到、口到、心到、手到。这“手到”就是读书…

php e error,E_ERROR定义与用法汇总

前言最近由于项目需要&#xff0c;需要读取一个含有中文的txt文档&#xff0c;完了还要保存文件。文档之前是由base64编码&#xff0c;导致所有汉字读取显示乱码。项目组把base64废弃之后&#xff0c;先后出现两个错误&#xff1a;ascii codec cant encode characters in posit…

delphi中的函数传参如何传枚举参数_我是这样使用SpringBoot(API传参)

spring boot 传参spring boot 中的Controller或者RestController接收参数的方法是一样的。这章目标是对几种常用的传参都写个例子。创建package: com.biboheart.demos.api&#xff0c;这个包里放置API接口的RestController在com.biboheart.demos.api包中创建一个class: ParamCo…

ssh-copy-id命令不存在_Redis(三)- 常见命令

步骤1:5种数据类型步骤2:String 字符串步骤3:List 列表步骤4:Hash 字典&#xff0c;哈希表步骤5:Set 集合步骤6:Sorted Set 有序集合步骤7:官方命令手册步骤 1 : 5种数据类型Redis目前有5种数据类型&#xff0c;分别是&#xff1a;String&#xff08;字符串&#xff09;List&am…