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

专注于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,一经查实,立即删除!

相关文章

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

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

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

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

CSAPP:第十一章 网络编程

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

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

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

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

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

【niop2016】

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

Linux 随机数

一、rand函数 rand函数的简单使用&#xff0c;rand()返回一个[0, RAND_MAX]中的随机数  #include <stdlib.h> #include <stdio.h> #include <time.h>int main() {printf("%d\n", RAND_MAX);//srand(time(NULL));for(int i 0; i < 5; i){print…

linux 2行数据为一条记录 该如何操作这一条记录_Linux 日志文件系统原来是这样工作的...

文件系统要解决的一个关键问题是怎样防止掉电或系统崩溃造成数据损坏&#xff0c;在此类意外事件中&#xff0c;导致文件系统损坏的根本原因在于写文件不是原子操作&#xff0c;因为写文件涉及的不仅仅是用户数据&#xff0c;还涉及元数据(metadata)包括 Superblock、inode bit…

JMeter - 如何创建可重用和模块化测试脚本

概述&#xff1a; 我的应用程序几乎没有业务关键流程&#xff0c;我们可以从中提出不同的业务工作流程。当我试图在JMeter中提出性能测试脚本时&#xff0c;我需要找到一些方法来创建可重用/模块化的测试脚本。这样我就可以创建不同的工作流程。 对于Ex&#xff1a; 让我们考虑…

请求支付宝渠道报错:40006,Insufficient Permissions,ISV权限不足

错误描述&#xff1a; 申请的是支付宝2.0产品&#xff08;如何区分支付宝产品是1.0还是2.0&#xff09;&#xff0c;请求支付宝渠道时&#xff0c;报错&#xff1a; {"code":"40006","msg":"Insufficient Permissions","sub_code…

idea中lombok的使用

1.安装插件 在File-Setting-Plugins-Browse Repostitories中搜索Lombok Plugin插件安装 安装完成先别急着重启&#xff0c;继续设置&#xff0c;在File-Setting-Build, Execution, Deployment-Compiler-Annotation Processors中点击Enable annotation processors 确定后重启ide…

是隐极电机_资料 | 发电机定子绕组端部动态特性试验详解

一、试验目的大型汽轮发电机运行过程中&#xff0c;定子端部受二倍工频(100Hz)的电磁激振力。如果定子端部的模态接近100Hz&#xff0c;将发生谐振&#xff0c;从而可能因振幅过大而发生结构松动、磨损、绝缘损坏等现象&#xff0c;甚至断裂等故障&#xff0c;严重威胁机组的安…

[导入]在C++ Builder3下实现程序自动运行的方法

文章来源:http://blog.csdn.net/nm/archive/2000/08/10/4403.aspx 转载于:https://www.cnblogs.com/zhaoxiaoyang2/archive/2000/08/10/816562.html

中动态路径加载_GOT段在linux系统中实现代码动态加载的作用和其他段的说明

上一节我们看到&#xff0c;当程序想调用系统函数时&#xff0c;在编译阶段无法确认被调用函数所在的虚拟地址。因此必须有机制让程序在运行过程中&#xff0c;在调用系统API的时候有办法去确定所调用的系统函数对应的入口地址&#xff0c;这就是代码运行时对应动态加载的过程。…

GitLab结合Eclipse的简单使用 - 20190211

需求&#xff1a; 移动端的值班经理视图调用了三个接口&#xff0c;需要在移动段的应用下加上三个接口的路由&#xff0c;分别是&#xff1a; /xxx-mvc/dutyView/getProviderSysDeal /xxx-mvc/dutyView/getSysAlarmData /xxx-mvc/dutyView/getSysStaffInfo package com.xxx.xxx…

中文整合包_MIMOSA2: 基于微生物组和代谢组数据的整合分析

MIMOSA2&#xff1a;基于微生物组和代谢组数据的整合分析MIMOSA2 升级自MIMOSA1。是 Borenstein 实验室(http://borensteinlab.com/ , 专注宏基因组系统 生物学)最新开发的工具。用于微生物群落和代谢组的整合分析&#xff0c;寻找微生物和代谢产物之间的关系。先前Borenstein …

python二级简书_12月4日,总结发现杯,备战python二级

上午看二级第一二章下午查询成绩夜晚看第三章做笔记&#xff0c;回看笔记总结&#xff1a;整体不是很理想&#xff0c;但感觉都比我高&#xff0c;呜呜呜他们的成绩一个个的都出来了&#xff0c;我的呢……为什么&#xff0c;还查不到&#xff0c;我知道我考的差&#xff0c;但…

二叉搜索时与双向链表python_【剑指offer】26 二叉搜索树与双向链表

- 题目描述输入一棵二叉搜索树&#xff0c;将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点&#xff0c;只能调整树中结点指针的指向。- 解题思路递归- Java实现/**public class TreeNode { int val 0; TreeNode left null; TreeNode right nul…