加载文件流_未关闭的文件流会引起内存泄露么?

专注于Java领域优质技术,欢迎关注

来自:技术小黑屋

最近接触了一些面试者,在面试过程中有涉及到内存泄露的问题,其中有不少人回答说,如果文件打开后,没有关闭会导致内存泄露。当被继续追问,为什么会导致内存泄露时,大部分人都没有回答出来。

本文将具体讲一讲 文件(流)未关闭与内存泄露的关系。

什么是内存泄露

  • 定义:当生命周期长的实例L 不合理地持有一个生命周期短的实例S,导致S实例无法被正常回收

举例说明

7e8c4a18cad38df798e00c01a939f986.png

上面的代码可能会发生内存泄露

  • 我们调用AppSettings.getInstance.setup()传入一个Activity实例
  • 当上述的Activity退出时,由于被AppSettings中属性mAppContext持有,进而导致内存泄露。

为什么上面的情况就会发生内存泄露

  • 以 Android 为例,GC 回收对象采用GC Roots强引用可到达机制。
  • Activity实例被AppSettings.sInstance持有
  • AppSettings.sInstance由于是静态,被AppSettings类持有
  • AppSettings类被加载它的类加载器持有
  • 而类加载器就是GC Roots的一种
  • 由于上述关系导致Activity实例无法被回收销毁。

验证是否引起内存泄露

因此,想要证明未关闭的文件流是否导致内存泄露,需要查看文件流是否是GC Roots强引用可到达。

示例代码1(辅助验证GC 发生)

a128de034e88c3eeed793d54990ec46b.png

示例代码2

1a7905ed8a0f9830a72cd3d6dea849ae.png
9d6a72c0a810b1739a9cb4b333c0ee98.png

这里我们这样操作

  1. 点击textview视图,触发多次testInputStream
  2. 过几秒后,我们执行heap dump。
  3. 我们使用 MAT 对上一步的dump文件进行分析(需进行格式转换)
7096c71e2637bb4b740333a2d1f7d30b.png

分析上图,我们发现

  • FileInputStream 只被 FinalizerReference 这个类(GC Root)持有
  • 上述持有的原因是,FileInputStream重写了finalize,会被加入到FinalizerReference的析构处理集合
  • 上述引用会随着Finalizer守护线程处理后解除,即FileInputStream实例彻底销毁。

所以,我们再来操作一波,验证上面的结论。

  • 然后利用工具执行强制GC回收
  • 过几秒后,我们执行heap dump。
  • 我们使用 MAT 对上一步的dump文件进行分析(需进行格式转换)
  • 堆分析文件,查找MyBufferedReader或者FileInputStream或者InputStreamReader 没有发现这些实例,说明已经GC回收
  • 出于谨慎考虑,我们按照包名查找java.io在排除无关实例外,依旧无法找到testInputStream中的实例。再次证明已经被GC回收

因而我们可以确定,正常的使用流,不会导致内存泄露的产生。

当然,如果你刻意显式持有Stream实例,那就另当别论了。

为什么需要关闭流

首先我们看一张图

dec917d9c923824b1265c7754d6388d0.png

如上图从左至右有三张表

  • file descriptor table 归属于单个进程
  • global file table(又称open file table) 归属于系统全局
  • inode table 归属于系统全局

从一次文件打开说起

当我们尝试打开文件/path/myfile.txt

1.从inode table 中查找到对应的文件节点

2.根据用户代码的一些参数(比如读写权限等)在open file table 中创建open file 节点

3.将上一步的open file节点信息保存,在file descriptor table中创建 file descriptor

4.返回上一步的file descriptor的索引位置,供应用读写等使用。

file descriptor 和流有什么关系

  • 当我们这样FileInputStream("/sdcard/a.txt") 会获取一个file descriptor。
  • 出于稳定系统性能和避免因为过多打开文件导致CPU和RAM占用居高的考虑,每个进程都会有可用的file descriptor 限制。
  • 所以如果不释放file descriptor,会导致应用后续依赖file descriptor的行为(socket连接,读写文件等)无法进行,甚至是导致进程崩溃。
  • 当我们调用FileInputStream.close后,会释放掉这个file descriptor。

因此到这里我们可以说,不关闭流不是内存泄露问题,是资源泄露问题(file descriptor 属于资源)。

不手动关闭会怎样

不手动关闭的真的会发生上面的问题么? 其实也不完全是。

因为对于这些流的处理,源代码中通常会做一个兜底处理。以FileInputStream为例

752b0542d6db7175ceb9f13a041dcc9f.png

是的,在finalize方法中有调用close来释放file descriptor.

但是finalize方法执行速度不确定,不可靠

所以,我们不能依赖于这种形式,还是要手动调用close来释放file descriptor。

关闭流实践

Java 7 之后,可以使用try-with-resource方式处理

379e6acb86dccad461b6f4e8ecfc53c0.png

Kotlin 可以使用use

3de6fac09a618a8449b3c1276b8f20e1.png

当然,还有最基础的手动关闭的形式

8c7e11954cc4e089774e7e8a204fa749.png

Reference

  • https://stackoverflow.com/questions/26541513/why-is-it-good-to-close-an-inputstream
  • https://www.reddit.com/r/learnjava/comments/577769/why_do_you_need_to_close_streams/

来自:https://droidyue.com/blog/2019/06/09/will-unclosed-stream-objects-cause-memory-leaks/

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

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

相关文章

[vue] vue组件之间的通信都有哪些?

[vue] vue组件之间的通信都有哪些? 父子Coms: 1/2/3 ..兄弟Coms: 4/5跨级Coms: 4/5/6/7props$emit/$on( $parents/$children ) / $refsVuexBus( provide/inject )( $attrs/$listeners )个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易&…

linux中配置phpcms v9 中的sphinx

#MySQL数据源配置,详情请查看:http://www.coreseek.cn/products-install/mysql/2 #请先将var/test/documents.sql导入数据库,并配置好以下的MySQL用户密码数据库34 #源定义56 source news_news7 {8 type mysql9 …

Microsoft Visio绘图

2000年微软公司收购同名公司后,Visio成为微软公司的产品。Microsoft Visio是Windows 操作系统下运行的流程图软件,它现在是Microsoft Office软件的一个部分。Visio可以制作的图表范围十分广泛,有些人利用Visio的强大绘图功能绘制地图、企业标…

[vue] 请描述下vue的生命周期是什么?

[vue] 请描述下vue的生命周期是什么? 生命周期就是vue从开始创建到销毁的过程,分为四大步(创建,挂载,更新,销毁),每一步又分为两小步,如beforeCreate,create…

HTTP返回码中301与302的区别

一.官方说法 301,302 都是HTTP状态的编码,都代表着某个URL发生了转移,不同之处在于: 301 redirect: 301 代表永久性转移(Permanently Moved)。 302 redirect: 302 代表暂时性转移(Temporarily Moved )。 这是很官方…

10截图时屏幕变大_手机上网课、开视频会议,如何让屏幕变大一点?

点击图片进入商城▲车载闪充49.9秒杀!Reno2 Z直降200元!真无线耳机团购可省130元!这个特殊时期很多伙伴和小O一样在家远程云办公、线上会议学生朋友们也是在家参加网上课程虽然现在的手机屏幕越来越大但总盯着手机还是难免眼酸但是掌握这个手…

mysql的命令行安装,忘记密码,密码重置问题

1.下载,安装msi 2.在MYSQL安装目录下,新建data目录 3.进入MYSQL的安装目录下,新建一个默认配置文件my.ini [mysql] # 设置mysql客户端默认字符集 default-character-setutf8 [mysqld] #设置3306端口 port 3306 # 设置mysql的安装目录 base…

电话邦php面试题及答案

程序设计; 1.200个数位于数组$a中,均为[1,199]之间的整数,仅有一个数和其他的重复,请用程序找出这个重复的数,算法尽量快速. 答案: function Repeat($a){ $unique_arr array_unique($a); $repeat_arr array_diff_assoc($a,$unique); return $repeat_arr; } $repeat_a…

分层和分段用什么符号_小编带你学直播——后牙树脂分层堆塑

后牙龋损过大,患者又不想做冠修复,树脂修补真的能挽救被龋坏侵蚀的牙体吗?补牙看起来简单,但是补好却难,同事用分层堆塑补的后牙窝沟分明,有点想学...本周小编为你推荐吕春阳老师——《后牙树脂分层堆塑》专…

CSAPP:第十一章 网络编程

CSAPP:第十一章 网络编程 11.1 客户端服务器模型11.2 全球IP因特网11.3 套接字接口 11.1 客户端服务器模型 每个网络应用都是基于客户端-服务器模型。采用这个模型,一个应用是由一个服务器进程和一个或者多个客户端进程组成。  客户端-服务器模型的基本…

[vue] 说下你对指令的理解?

[vue] 说下你对指令的理解? 指令 (Directives) 是带有 v- 前缀的特殊 attribute。指令 attribute 的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响&a…

给数据库字段增加前缀

update users set mobile concat(86-, mobile)

动态表格数据序号从1开始_EXCEL对面的表姐看过来,你真的会给表格添加序号吗?...

原创作者: EH看见星光 转自:Excel星球哈罗,大家好,我是星光,今天给大家总结分享的表格技巧是……序号。什么是序号?序号就是一二三四五上山打老虎……一二三四一二三四像首歌……一二三四二二三四脖子扭扭屁…

[vue] 说说你对MVC、MVP、MVVM模式的理解

[vue] 说说你对MVC、MVP、MVVM模式的理解 MVVM用视图模型代替了MVP中的展示器,视图模型和视图实现了双向绑定,当视图发生变化的时候视图模型也会发生改变,当视图模型变化的时候视图也随之变化。MVP用展示器代替了控制器,而展示器…

设置公共请求参数_基于分布式锁的防止重复请求解决方案(值得收藏)

关于重复请求,指的是我们服务端接收到很短的时间内的多个相同内容的重复请求。而这样的重复请求如果是幂等的(每次请求的结果都相同,如查询请求),那其实对于我们没有什么影响,但如果是非幂等的(每次请求都会对关键数据造成影响&am…

linux:vi 替换命令

:s/^.*$/\L&/100 ##将100行内的小写转换成大写 vi/vim 中可以使用 :s 命令来替换字符串。 :s/vivian/sky/ 替换当前行第一个 vivian 为 sky :s/vivian/sky/g 替换当前行所有 vivian 为 sky :n,$s/vivian/sky/ 替换第 n 行开始到最后一行中每一行的第…

[vue] 你有写过自定义指令吗?自定义指令的生命周期(钩子函数)有哪些?

[vue] 你有写过自定义指令吗?自定义指令的生命周期(钩子函数)有哪些? bind inserted update componentUpdated unbind个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易, 但坚持一定很酷。欢迎…

【niop2016】

D1T1 玩具谜题 my总结: 【luogu1563】【niop2016】玩具谜题 题面 模拟!!! D1T2 天天爱跑步 my总结: 暂无 题面 我太弱了还搞不出来 暴力也不想写 D1T3 换教室 my总结:【niop2016】【luogu1600】…

linux 复制文件或者文件

linux下文件的复制、移动与删除命令为:cp,mv,rm 一、文件复制命令cp 命令格式:cp [-adfilprsu] 源文件(source) 目标文件(destination) cp [option] source1 source2 source3 ... directory 参数说明&…

[vue] 你有看过vue的源码吗?如果有那就说说看

[vue] 你有看过vue的源码吗?如果有那就说说看 看过 看不懂个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易, 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题