大家好,本文主要讲Java内存泄漏的故障排除和解决方法。有兴趣的同学过来看看,如果对你有帮助记得收藏。
前言
Java最棒的特性之一是垃圾收集机制。它不需要像C一样手动管理内存,所以作为Java程序员我很开心。只是New New New,反正Java会自动收集过期的对象。
然后Java自动管理内存,怎么会有内存泄漏呢?Jvm有bug吗?别急,慢慢听我说。
1. 怎么判断可以被回收
我们先来了解一下Jvm是如何确定一个对象可以回收的。一般有两种方式,一种是引用计数法,另一种是可达性分析。
引用计数法:每个对象都有一个引用计数属性。当添加一个引用时,计数增加1;当释放参考时,计数减1;当计数为0时,可以回收。
这个方法看起来相当简单,但是如果A指B and B指A,那么即使它们不再被使用,交叉引用计算器=1也永远不能被回收。
这种方法比较简单,不能解决对象间循环引用的问题。
可达性分析(Reachability Analysis):从GC根向下搜索,搜索的路径叫做引用链。当一个对象在没有任何引用链的情况下连接到GC根时,证明该对象不可用,然后虚拟机判断它是可回收的对象。
可达性分析可以解决循环引用的问题。
那么什么是gc根对象呢?
虚拟机堆栈中引用的对象
方法中类的静态属性引用的对象。
方法中常数引用的对象
JNI[本机]在本地方法堆栈中引用的对象
目前,大多数主流虚拟机使用可达性分析来确定对象是否可以被GC回收。
2. 什么情况下会出现内存泄漏
既然可达性分析看起来很牛逼,怎么还会有内存泄漏?我们来看看内存泄漏的定义。
内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。
有可能这个对象已经不在使用了,但是还有其他对象保留对这个对象的引用,这将导致GC无法回收这个对象。在这种情况下,会发生内存泄漏。
写一个程序让出现内存泄漏
当长寿命对象持有对短寿命对象的引用时,很可能发生内存泄漏。虽然不再需要短寿命对象,但它不能被回收,因为长寿命对象持有它的引用。
简单公共类{
Object对象;
公共void方法1(){
Object=new Object();
//.其他代码
}
}
这里的object实例,实际上我们期望它只作用于method1()方法,在其他任何地方都不会用到。但在method1()方法执行完成后,object对象分配的内存不会立即被认为是可以释放的对象,只有在简单类创建的对象释放后才会被释放。严格来说,这是内存泄漏。
解决方案是在method1()中使用object作为局部变量。
简单公共类{
Object对象;
公共void方法1(){
Object=new Object();
//.其他代码
object=null
}
}
当然你可能觉得这个方法不会有太大的影响,但是如果在某些项目中一个方法一分钟被调用上万次,就会出现明显的内存泄漏。
集合中的内存泄漏,如HashMap、ArrayList等。这些对象经常会有内存泄漏。比如当它们被声明为静态对象时,它们的生命周期会和应用程序一样长,这就容易导致内存不足。
下面是一个集合内存泄漏的例子。
向量v=新向量(10);
for(int I=1;i100我)
{
Object o=new Object();
五. add(o);
o=null
}
//此时,所有的Object对象都没有被释放,因为变量v引用了这些对象。
在这个例子中,我们循环应用Object对象,并将应用的对象放入一个Vector中。如果我们只释放引用本身,那么Vector仍然引用对象,所以这个对象对于GC是不可回收的。
因此,如果对象在添加到Vector后必须从Vector中删除,最简单的方法是将Vector对象设置为null。
以上两种是最常见的内存泄漏情况。当然也有一些内存泄露的例子,这里就不多举了。有兴趣的同学可以在网上找资料。
3. 如何检测内存泄漏
3.1 模拟内存泄漏代码
包com . wenxiaowu . solution;
导入Java . util . ArrayList;
导入Java . util . list;
/**
* Java内存泄漏模拟
*/
公共类TestMemoryLeak {
公共静态void main(String[] args)引发InterruptedException {
ListSimpleObject list=new ArrayList();
runtime run=runtime . get runtime();
int I=1;
while (true) {
simple object simple object=new simple object();
list . add(simple object);
simpleObject=null
if (i % 1000==0) {
System.out.print(i):最大内存=' run.maxMemory()/1024/1024 'M,');
system . out . print(' allocated memory=' run . total memory()/1024/1024 ' m ');
System.out.print('剩余空间内存=' run . free memory()/1024/1024 ' M ');
System.out.println('最大可用内存='(run . maxmemory()-run . total memory()run . free memory())/1024/1024 ' m ');
}
thread . sleep(1);
}
}
}
类SimpleObject {
//初始化一个占用1M内存的数组
private int[]arr=new int[1024 * 8];
public int[] getArr() {
返回arr
}
}
3.2 生成dump文件
Java-jar-Xmx1G-Xms1G-XX:heapdumponotofmemoryerror-XX:HeapDumpPath=/tmp wenxiaowu-Java . jar
3.3 用JProfile加载dump文件
如你所见,红框中的int数组占据了大部分空间。
3.4 定位最大占用内存的原始位置
最后,在main方法中创建了这个对象。
解决办法
使用后先删除对应的引用,然后将对象设置为null,这样内存就可以正常回收了。
总结
这篇关于Java内存泄漏的故障排除和解决方法的文章到此为止。有关Java内存泄漏的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望你以后能支持我们!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。