Effective Java笔记(7)消除过期的对象引用

news2024/11/26 10:31:47

        当你从手工管理内存的语言(比如 C 或 C++)转换到具有垃圾回收功能的比如 Java 语言时,程序员的工作会变得更加容易,因为当你用完了对象之后,它们会被自动回收 。 当你第一次经历对象回收功能的时候,会觉得这简直有点不可思议 。 它很容易给你留下这样的印象, 认为自己不再需要考虑内存管理的事情了,其实不然 。

请看下面这个简单的战实现的例子:

        这段程序中并没有很 明显的错误 。 无论如何测试,它都会成功地通过每一项测试,但是这个程序中隐藏着一个问题 。 不严格地讲,这段程序有一个“内存泄漏”,随着垃圾回收器活动的增加,或者由于内存占用的不断增加,程序性能的降低会逐渐表现出来 。 在极端的情况下,这种内存泄漏会导致磁盘交换( Disk Paging ),甚至导致程序失败( OutOfMemoryError 错误),但是这种失败情形相对比较少见 。

        那么,程序中哪里发生了内存泄漏呢? 如果一个栈先是增长 ,然后再收缩 , 那么,从栈中弹出来的对象将不会被当作垃圾回收,即使使用栈的程序不再引用这些对象,它们也不会被回收 。 这是因为栈内部维护着对这些对象的过期引用( obsolete reference ) 。 所谓的过期引用,是指永远也不会再被解除的引用 。 在本例中,凡是在 elements 数组的“活动部分”(active portion )之外的任何引用都是过期的 。 活动部分是指 elements 中下标小于 size 的那些元素 。

        在支持垃圾回收的语言中,内存泄漏是很隐蔽的(称这类内存泄漏为“无意识的对象保持”( unintention al object retention )更为恰当) 。 如果一个对象引用被无意识地保留起来了,那么垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象所引用的所有其他对象 。 即使只有少量的几个对象引用被无意识地保留下来,也会有许许多多的对象被排除在垃圾回收机制之外,从而对性能造成潜在的重大影响 。

        这类问题的修复方法很简单 : 一旦对象引用已经过期,只需清空这些引用即可 。 对于上述例子中的 Stack 类而言,只要一个单元被弹出栈,指向它的引用就过期了 。pop 方法的修订版本如下所示:

        清空过期引用的另一个好处是,如果它们以后又被错误地解除引用,程序就会立即抛出 NullPointerException 异常,而不是悄悄地错误运行下去 。 尽快地检测出程序中的错误总是有益的。

        当程序员第一次被类似这样的问题困扰的时候,他们往往会过分小心 : 对于每一个对象引用,一旦程序不再用到它,就把它清空 。 其实这样做既没必要,也不是我们所期望的,因为这样做会把程序代码弄得很乱 。 清空对象引用应该是一种例外 , 而不是一种规范行为 。 消除过期引用最好的方法是让包含该引用的变量结束其生命周期 。 如果你是在最紧凑的作用域范围内定义每一个变量,这种情形就会自然而然地发生 。

        那么,何时应该清空引用呢?Stack 类的哪方面特性使它易于遭受内存泄漏的影响呢?简而言之,问题在于,Stack 类自己管理内存 。 存储池( storage pool )包含了 elements 数组(对象引用单元,而不是对象本身)的元素 。 数组活动区域(同前面的定义)中的元素是已分配的( allocated ),而数组其余部分的元素则是自由的( free ) 。 但是垃圾回收器并不知道这一点;对于垃圾回收器而言,elements 数组中的所有对象引用都同等有效 。 只有程序员知道数组的非活动部分是不重要的 。 程序员可以把这个情况告知垃圾回收器,做法很简单:一旦数组元素变成了非活动部分的一部分,程序员就手工清空这些数组元素 。

        一般来说 ,只要类是自己管理内存,程序员就应该警惕内存泄漏问题 。 一旦元素被释放掉,则该元素中包含的任何对象引用都应该被清空 。

        内存泄漏的另一个常见来源是缓存 。 一旦你把对象引用放到缓存中,它就很容易被遗忘掉,从而使得它不再有用之后很长一段时间内仍然留在缓存中 。 对于这个问题,有几种可能的解决方案 。 如果你正好要实现这样的缓存:只要在缓存之外存在对某个项的键的引用,该项就有意义,那么就可以用 WeakHashMap 代表缓存;当缓存中的项过期之后,它们就会自动被删除 。 记住只有当所要的缓存项的生命周期是由该键的外部引用而不是由值决定时,WeakHashMap 才有用处。

        更为常见的情形则是,“缓存项的生命周期是否有意义”并不是很容易确定,随着时间的推移,其中的项会变得越来越没有价值 。 在这种情况下,缓存应该时不时地清除掉没用的项 。 这项清除工作可以由一个后台线程( 可能是 ScheduledThreadPoolExecutor )来完成,或者也可以在给缓存添加新条目的时候顺便进行清理 。LinkedHashMap 类利用它的 removeEldestEntry 方法可以很容易地实现后一种方案 。 对于更加复杂的缓存,必须直接使用 java.lang.ref 。

        内存泄漏的第三个常见来源是监听器和其他回调 。 如果你实现了一个 API,客户端在这个 API 中注册回调,却没有显式地取消注册,那么除非你采取某些动作,否则它们就会不断地堆积起来 。 确保回调立即被当作垃圾回收的最佳方法是只保存它们的弱引用( weak reference ) ,例如,只将它们保存成 WeakHashMap 中的键 。

        由于内存泄漏通常不会表现成明显的失败,所以它们可以在一个系统中存在很多年 。往往只有通过仔细检查代码,或者借助于 Heap 剖析工具( Heap Profiler )才能发现内存泄漏问题 。 因此,如果能够在内存泄漏发生之前就知道如何预测此类问题,并阻止它们发生,那是最好不过的了。

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

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

相关文章

中国人民大学与加拿大女王大学金融硕士——引领你走在金融行业前沿

金融是现代经济的血脉,而金融行业高质量发展取决于金融人才。新常态下,中国经济进入新的阶段,同时也对金融人才培养提出了新的要求。针对在金融行业沉淀多年的在职人士而言,是否需要更加系统化的学习金融知识呢,中国人…

Python自动化之win32利器pywin32

文章目录 前言一、GUI1.1 获取、关闭窗口1.2 窗口截图1.3 创建窗口 二、文件、目录2.1 查找2.2 创建2.3 复制/移动2.4 删除2.5 读取/写入 三、服务3.1 查找3.2 安装 四、案例4.1 自动发送微信消息4.2 Excel 操作4.3 监控文件夹 参考 前言 PyWin32 是一个Python库,用…

【vue】路由的搭建以及嵌套路由

目的:学习搭建vue2项目基础的vue路由和嵌套路由 1.npm 安装 router npm install vue-router3.6.52.src下新建文件夹router文件夹以及文件index.js index.js import Vue from vue import VueRouter from "vue-router" import Home from ../views/Home.…

【Linux】- 组管理和权限管理

组管理和权限管理 1.1 Linux 组基本介绍1.2 权限的基本介绍 1.1 Linux 组基本介绍 在 linux 中的每个用户必须属于一个组,不能独立于组外。在 linux 中每个文件 有所有者、所在组、其它组的概念。 所有者所在组其它组改变用户所在的组 文件/目录 所有者 一般为文…

关于Windows 11 docker desktop 运行doris 容器时vm.max_map_count=2000000的设置问题

需要一个简单的测试环境,于是准备用docker启动一个1fe 1be的简单玩一下 如果be容器启动后再去修改 /etc/sysctl.conf sysctl -w vm.max_map_count2000000 这个参数是没用的,be仍然会启动失败 这时可以打开cmd wsl --list C:\Users\pc>wsl --list …

Docker基础——初识Docker

Docker架构 Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。 Docker 客户端(Client) : Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。Docker 主机(Host…

MMDeploy部署YOLOX-x模型

环境搭建 本文初始环境为PyTorch 2.0.0、Python 3.8(ubuntu20.04)、Cuda 11.8 OpenMMLab基础环境 首先安装OpenMMLab基础环境,以下代码均在命令窗口下输入 pip install openmim mim install mmcv-full mim install "mmengine0.7.2"git clone https://…

太阳能供电户外视频远程监控4G无线物联网工业路由器ZR3000

太阳能供电技术常被应用于环保节能的项目中,太阳能具备节能环保、寿命长、性能稳定、维护成本低等特点,被各行各业采纳使用。大多数太阳能应用于户外,存在监控点距离较远、取电困难、宽带光纤布线成本高、环境恶劣等问题,现场还有…

ansible使用playbook剧本

目录 一、执行配置文件 1、修改hosts文件 2、编写yml脚本 3、语法检查[rootansible ~] ansible-playbook --syntax-check ansible.yml 4、预测试 5、执行命令 一、执行配置文件 Playbook配置文件使用YAML语法,具有简介明了,结构清晰等特点。Playbo…

对OpenAI重拳出击!美国政府出手「开源」ChatGPT,Altman惊慌连发3推

FTC突然对OpenAI展开调查,Altman连发3推澄清。FTC对阵OpenAI的大戏正缓缓拉开帷幕。 重磅!美国联邦贸易委员会的调查说来就来! 调查对象不是别人,正是风头正旺的OpenAI。 一封长达20页的调查要求书直接给了Sam Altman当头棒喝。…

【并发编程的艺术读书笔记】从内存图来理解java是如何执行多线程的

从内存图来理解java是如何执行多线程的 一、内存图简介 众所周知,java类中的成员变量会保存到方法区、java运行时的方法会存入栈中,随之方法中的局部变量也是存储在栈中的,引用类型(new出来的对象)存储在堆内存中。下…

【C++/嵌入式笔试面试八股】二、24.TCP三次握手四次挥手 | TCP可靠性

TCP三次握手四次挥手 64.TCP头部中有哪些信息?❤️ TCP数据报格式(左图) UDP数据报格式也放这(右图),不具体解释了。 结合三次握手四次挥手来看 端口: 区分应用层的不同应用进程 扩展:应用程序的端口号和应用程序所在主机的 IP 地址统称为 socket(套接字),IP:端口…

Linux - 安装nacos 2.1.0

安装包下载 网址为 https://github.com/alibaba/nacos/tags 点击访问 本人选择的nacos版本为2.1.0 与之对应的spring代码版本为 <spring.boot.version>2.3.12.RELEASE</spring.boot.version> <spring.cloud.version>Hoxton.SR12</spring.cloud.version…

运输层(TCP运输协议相关)

运输层 1. 运输层概述2. 端口号3. 运输层复用和分用4. 应用层常见协议使用的运输层熟知端口号5. TCP协议对比UDP协议6. TCP的流量控制7. TCP的拥塞控制7.1 慢开始算法、拥塞避免算法7.2 快重传算法7.3 快恢复算法 8. TCP超时重传时间的选择8.1 超时重传时间计算 9. TCP可靠传输…

如何在vscode中debug python代码,包括如何优雅地传入多个参数

Visiul Studio Code, 简称vscode&#xff0c;是一款轻量级代码编辑器&#xff0c;其丰富的扩展程序使得其可以方便地作为任何语言的编辑器。 本文将讲述如何在vscode中对python脚本文件进行debug。 本文主要包括debug的两种方式&#xff1a; 基本debugging(basic debugging)…

咖啡店小程序怎么做

咖啡店小程序功能介绍 咖啡店小程序是一款专为咖啡店打造的移动应用程序&#xff0c;旨在提供更便利、高效的服务体验。以下是该小程序的主要功能介绍&#xff1a; 1. 菜单浏览&#xff1a;用户可以通过小程序浏览咖啡店提供的各种咖啡、茶和小吃菜单&#xff0c;包括详细的产…

Docker基础——Centos7安装Docker

0.安装Docker Docker 分为 CE 和 EE 两大版本。CE 即社区版&#xff08;免费&#xff0c;支持周期 7 个月&#xff09;&#xff0c;EE 即企业版&#xff0c;强调安全&#xff0c;付费使用&#xff0c;支持周期 24 个月。 Docker CE 分为 stable test 和 nightly 三个更新频道…

速通sklearn库

速通sklearn库 前言 ​ 最近在复习之前学习过的知识点&#xff0c;因此想到把学过的总结一下&#xff0c;方便后面再次复习&#xff0c;所以有了这个系列。 说明 ​ 由于标题写的是“速通”&#xff0c;因此我的想法是可以让大家看完这篇文章&#xff0c;可以上手matplotlib库&…

FCPX插件-复古老电影胶片边框幻灯片照片展示介绍动画 Emotion Slides

Emotion Slides是一款fcpx插件&#xff0c;可以制作复古老电影胶片边框幻灯片照片展示介绍动画&#xff0c;完全自定义任意数量的场景&#xff0c;完全定制的控制器&#xff0c;7个独特的场景准备&#xff0c;易使用简单&#xff0c;只需拖放。 Emotion Slides插件的主要功能包…

【网络编程】传输层协议——UDP协议

文章目录 一、传输层的意义二、端口号2.1 五元组标识一个通信2.2 端口号范围划分2.3 知名端口号2.4 绑定端口号数目问题2.5 pidof & netstat命令 三、UDP协议3.1 UDP协议格式3.2 如何理解报头&#xff1f;3.3 UDP协议的特点3.4 UDP缓冲区3.5 UDP传输最大长度 一、传输层的意…