纳尼,Java 存在内存泄泄泄泄泄泄漏吗?
01. 怎么回事?
纳尼,Java 不是自动管理内存吗?怎么可能会出现内存泄泄泄泄泄泄漏!
Java 最牛逼的一个特性就是垃圾回收机制,不用像 C++ 需要手动管理内存,所以作为 Java 程序员很幸福,只管 New New New 即可,反正 Java 会自动回收过期的对象。。。
那么 Java 都自动管理内存了,那怎么会出现内存泄漏,难道 Jvm 有 bug? 不要急,且听我慢慢道来。。
02. 怎么判断可以被回收
先了解一下 Jvm 是怎么判断一个对象可以被回收。一般有两种方式,一种是引用计数法,一种是可达性分析。
引用计数法:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。
这个办法看起来挺简单的,但是如果出现 A 引用了 B,B 又引用了 A,这时候就算他们都不再使用了,但因为相互引用 计算器=1 永远无法被回收。
此方法简单,无法解决对象相互循环引用的问题。
可达性分析(Reachability Analysis):从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是不可用的,那么虚拟机就判断是可回收对象。
可达性分析可以解决循环引用的问题。
那么 gc roots 对象是哪些呢
- 虚拟机栈中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI[即一般说的Native]引用的对象
目前主流的虚拟机中大多使用可达性分析的方式来判定对象是否可被 GC 回收。
03. 什么情况下会出现内存泄漏
既然可达性分析好像已经很牛逼的样子了,怎么可能还会出现内存泄漏呢,那我们再来看一下内存泄漏的定义。
内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。
有可能此对象已经不使用了,但是还有其它对象保持着此对象的引用,就会导致 GC 不能回收此对象,这种情况下就会出现内存泄漏。
写一个程序让出现内存泄漏
①长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收。
public class Simple {
Object object;
public void method1(){
object = new Object();
//...其他代码
}
}
这里的 object 实例,其实我们期望它只作用于 method1() 方法中,且其他地方不会再用到它,但是,当method1()方法执行完成后,object 对象所分配的内存不会马上被认为是可以被释放的对象,只有在 Simple 类创建的对象被释放后才会被释放,严格的说,这就是一种内存泄露。
解决方法就是将 object 作为 method1() 方法中的局部变量。
public class Simple {
Object object;
public void method1(){
object = new Object();
//...其他代码
object = null;
}
}
当然大家有可能会想就这一个方法也不会有多大影响,但如果在某些项目中,一个方法在一分钟之内调用上万次的时候,就会出现很明显的内存泄漏现象。
②集合中的内存泄漏,比如 HashMap、ArrayList 等,这些对象经常会发生内存泄露。比如当它们被声明为静态对象时,它们的生命周期会跟应用程序的生命周期一样长,很容易造成内存不足。
下面给出了一个关于集合内存泄露的例子。
Vector v=new Vector(10);
for (int i=1;i<100; i++)
{
Object o=new Object();
v.add(o);
o=null;
}
//此时,所有的Object对象都没有被释放,因为变量v引用这些对象。
在这个例子中,我们循环申请 Object 对象,并将所申请的对象放入一个 Vector 中,如果我们仅仅释放引用本身,那么 Vector 仍然引用该对象,所以这个对象对 GC 来说是不可回收的。
因此,如果对象加入到 Vector 后,还必须从 Vector 中删除,最简单的方法就是将 Vector 对象设置为 null。
以上两种是最常见的内存泄漏案例。当然还有一些内存泄漏的例子,这里就不再一一例举了,感兴趣的同学可以在网上找找资料。
04. 内存泄漏和内存溢出
很多同学总是搞不清楚,内存泄漏和内存溢出的区别,它俩是两个完全不同的概念, 它们之间存在一些关联。
内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现 out of memory;
内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
所以内存泄漏可能会导致内存溢出,但内存溢出并不完全都是因为内存泄漏,也有可能使用了太多的大对象导致。
05. 如何检测内存泄漏
最后一个重要的问题,就是如何检测 Java 的内存泄漏。目前,我们通常使用一些工具来检查 Java 程序的内存泄漏问题。
市场上已有几种专业检查 Java 内存泄漏的工具,它们的基本工作原理大同小异,都是通过监测 Java 程序运行时,所有对象的申请、释放等动作,将内存管理的所有信息进行统计、分析、可视化。开发人员将根据这些信息判断程序是否有内存泄漏问题。
这些工具包括 Plumbr 、Eclipse Memory Analyzer、JProbe Profiler、JVisualVM 等。
06. 最后
以上内容其实是我曾经经常面试的内容之一,通过一系列的问题考察 Java 程序员对 Jvm 的理解。
比如我通常会问面试者,Java 中存在内存泄漏吗?大部分人都会回答存在,接着我会问如果让你写一个程序让内存泄漏,你会怎么写?大部分程序员就回答不上来了。
如果面试者可以回答上面的问题,我会接着和面试者聊聊,内存泄漏和内存溢出他们之间是否存在联系 、以及在日常工作中如何避免写出内存泄漏的代码 、如果生产出现 Jvm 相关问题时,排查问题的思路和步骤等等。
这些问题在我的博客中都有答案,早些年写了一系列关于 Jvm 的文章,大家如果感兴趣的话接下来继续去阅读,http://www.ityouknow.com/java.html。
如果大家觉得在手机上看着更方便,可以关注:Java 极客技术公号,已经输出了一些 JVM 文章,我博客中的 Jvm 系列文章也都会推送到这个公号中。
关注一下又不会怀孕
参考出处:
https://lovoedu.gitee.io/javablog/2017/08/27/20170827/
https://www.ibm.com/developerworks/cn/java/l-JavaMemoryLeak/index.html
纳尼,Java 存在内存泄泄泄泄泄泄漏吗?的更多相关文章
- 小白请教几个关于Java虚拟机内存分配策略的问题
最近在看周志明所著的<深入理解Java虚拟机>,有几个问题不太明白,希望对虚拟机有研究的哥们儿帮我解答一下.先说一下我进行试验的环境: 操作系统:Mac OS X 10.11.6 EI C ...
- java中内存分配策略及堆和栈的比较
Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ...
- Java的内存机制
Java 把内存划分成两种:一种是栈内存,另一种是堆内存.在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空 ...
- Java堆内存的十个要点
Java中的堆空间是什么? 当Java程序开始运行时,JVM会从操作系统获取一些内存.JVM使用这些内存,这些内存的一部分就是堆内存.堆内存通常在存储地址的底层,向上排列.当一个对象通过new关键字或 ...
- java线程内存模型,线程、工作内存、主内存
转自:http://rainyear.iteye.com/blog/1734311 java线程内存模型 线程.工作内存.主内存三者之间的交互关系图: key edeas 所有线程共享主内存 每个线程 ...
- 说说Java的内存
首先,我们来看一段程序内存溢出的代码: import java.util.ArrayList; import java.util.List; public class TestMemoryLeak { ...
- 「轉」Java的内存机制
0.参考资料: http://www.j2megame.org/index.php/content/view/2246/125.html 1.Java的内存机制 Java 把内存划分成两种:一种是栈内 ...
- Java虚拟机内存管理机制
自动内存管理机制 Java虚拟机(JVM)在执行Java程序过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有的区 ...
- java堆内存与栈内存
java的内存分为两种,堆内存与栈内存: 堆内存用来存放数组和new的对象,比如一个文件,字节流是存放在堆中,栈内存为这个文件开辟一个索引,也就是这个文件的地址,并且保存在栈中.对象由GC处理释放内存 ...
随机推荐
- BUPT复试专题—List(2015)
题目描述 在该LIST上实现3种操作 1.append x在该LIST末尾添加x,x是32位整数 2.pop删除该LIST末尾的数 3.find i寻找第i个数,若i为负数表示寻找倒数第i个数,例如i ...
- 【转】利用shell命令操作Memcached
原文: 张宴的博客 —— http://zyan.cc/post/384/ -------------------------------------------------------------- ...
- 关于HTML中文乱码问题
系统:ubuntu 14.04 软件:bluefish 一.乱码原因 1.不同编码内容混杂:HTML乱码是因为html编码问题照成(常见gb2312与utf-8两种编码内容同一时候存在照成) 2.未设 ...
- 用Perl发送邮件小例子
据传,Perl发送邮件有很多方案,但我只会用Mail::Sender这种方式,也就只能简单谈谈这种方式. 在参考众多网页后,程序书写如下: #!/usr/bin/perl -w use Mail::S ...
- 优化你的服务器Apache、MySQL、PHP
硬件上的考虑其实起50%的作用,当然是越快越好.如果不知道哪个快,就换成越贵越好.可实际上不可能做到这些,因为银子有限,所以按照这个顺序考虑:内存越大越好->硬盘SCSI好于SATA->C ...
- 【转载】一致性哈希算法(consistent hashing)
一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简 单哈 ...
- 全文索引--自己定义chinese_lexer词典
本文来具体解释一下怎样自己定义chinese_lexer此法分析器的词典 初始化数据 create table test2 (str1 varchar2(2000),str2varchar2(2000 ...
- 项目Beta冲刺(团队5/7)
项目Beta冲刺(团队5/7) 团队名称: 云打印 作业要求: 项目Beta冲刺(团队) 作业目标: 完成项目Beta版本 团队队员 队员学号 队员姓名 个人博客地址 备注 221600412 陈宇 ...
- Xamarin.Android 记事本(二)自定义AlertDialog
导读 1.自定义一个AlertDialog 2.添加一条数据 正文 记事本应当有一个添加功能,这里我打算在右上角放一个item,然后点击这个item弹出一个对话框,输入名称,点击确定跳转到另一个act ...
- HDU1241 Oil Deposits —— DFS求连通块
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1241 Oil Deposits Time Limit: 2000/1000 MS (Java/Othe ...