java 内存泄露问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 内存泄露问题相关的知识,希望对你有一定的参考价值。
一条java进程,如果System.exit(0)来杀掉该进程,那该进程原来占用的内存资源就释放掉了吗?有可能产生内存泄露的问题吗?
Java中虽然使用了gc策略,但事实上还是会出现内存泄漏现象的,java因此还提出了弱引用等局部解决方案。但楼主说的System.exit(0)是不会形成内存泄漏的。
其实这里都是两个范畴的内存了。楼上以及我开始说的Java中的内存是指虚拟机的内存,映射到宿主机可以有各种实现,虽然一般也是映射到内存。 而System.exit(0)会析构掉虚拟机,也就是把这个虚拟的机器都拆了,也就无从谈起虚拟机内存泄漏不泄漏的概念,正所谓皮之不存,毛将焉附。而问题是宿主机的内存是否泄漏了。从原理上说,虚拟机运行时,不管执行怎样的指令,映射到宿主机器资源,都回在机器被拆掉时释放。当然,从实现上说,如果宿主操作系统,或者JVM有bug,当然有可能造成内存泄漏,但和java程序员写的客户程序无关。(补充:包括在宿主机内杀java进程,其资源回收问题是操作系统和java平台的责任。我们在古老的操作系统经常会遇到文件没正常关闭之类的问题,但现在的操作系统这些问题应该不会很大,也就是宿主机其实也有一定的回收机制,包括内存回收,但着本身不是内存泄漏的范畴,内存泄漏是指程序运行时的客户程序造成的内存资源失控。当客户程序退出时的问题,就是操作系统设计的范畴了) 参考技术A System.exit(0) 不会造成能存泄漏,因为进程已经退出,操作系统回收了所有该进程使用的所有内存。
gc() 保证会释你已经不再使用的类所使用的内存。
但是,你能保证在调用gc()的类中,这个类已经不再使用了么??
再简单的类中,一目了然。
在复杂的类中呢?类的引用,数组引用,变量引用,向量中的引用,如果不为空,gc()都不会释放内存。
换句话说:
vs = null; //下一轮内存回收的时候vs会释放内存
gc(); //立即回收内存
良好的编码,在java中不会造成内存漏洞! 参考技术B 据我了解,System.exit(0)不是杀掉一个线程,而是杀掉一个进程。
一个进程可以比喻为一个程序的启动,一个这个程序启动后可以向cpu申请若干其他的时间片,就是线程。
java中定义线程对象使用Thread类,而该对象的销毁可以用其dispose方法,
System.exit(0),看名字就知道,调用该方法的对象不是一个单一的线程,而是主线程,这个主线程代表了整个进程。
所以System.exit(0)杀掉线程的说法是错的,下面再来说说java的垃圾回收机制。没错,理论上说java可以自动释放掉不用的内存空间,但是他不是即时的,在虚拟机中有一个单独的线程,隔一段时间就会检查所有资源的使用情况,然后释放掉申请过,但现在已经不同的。
gc()方法的作用和这个线程的释放功能是一样的,但是即使主动调用gc方法,也不会立即去释放内存,他会在系统相对稍微松弛的时候才去做。
如果要将一个线程申请的所有空间都释放掉,最好的方法是将所有在该线程运行中申请过的对象都置null,这样可以在当时就达到释放的效果。
需要注意的是,数组对象的释放不能一蹴而就,而应该依次释放其所有成员,举例如下:
如有定义
Vector[] vs = new Vector[10];
则释放时应该为
for(int i=0;i<10;i++)
vs[i] = null;
vs = null;
这样做可以在第一时间得到最大限度的空闲空间,而调用gc()方法则不能保证
如果未作上述操作,在多线程程序中直接调用System.exit(0),虽然也可以达到全部释放的目的,但是却存在一定隐患。建议如果是大型的分布式项目,可以不考虑这些,如果是相对小型的软件系统,在这方面应该多考虑一些,尽量做好,虽然增加了代码量,但程序要变得健壮许多。 参考技术C 这样做jvm会调用garbage collector回收内存,如果说jvm会不会buffer overflow,只能说任何c写的东西都有可能会buffer overflow,jvm是c写的 参考技术D 楼上几位达人讲的很详细了, 我路过~
JAVA中内存泄露和内存溢出
一、为什么要了解内存泄露和内存溢出
1.内存泄漏一般是程序员编写的代码有误导致的,了解内存泄漏的情况可以避免不必要的内存泄漏,让程序员提高自己编码水平。
2.通过了解内存溢出常见情况,可以快速准确地找到问题所在,缩短解决问题的时间。
二、内存泄漏和内存溢出的概念区分
1.内存泄漏,指的是,程序动态分配内存给一些临时对象,但是这些临时对象却没有GC所回收,始终占内存,即使没用了也始终占着内存,这就是内存泄漏。
2.内存溢出,指的是,没有被分配到足够的内存而导致的错误。
注意:看来内存泄漏是可能导致内存溢出的一种原因,并不是唯一原因。
三、内存泄漏的几种场景:
1.生命周期较长的对象中存了生命周期短的对象
这是内存泄漏的场景中最常见的一种,例如,在全局静态map中存了局部变量没有清空操作,随着时间的推移,map越来越大,因此造成内存泄漏。
2.修改了HashSet中对象计算哈希值的字段
当对象存入HashSet集合以后,就不能修改计算哈希值的字段了,否则修改后的哈希值与最初存入的哈希值就不同了。在这样的情况下,即使是在contains方法中使用该对象的当前引用作为参数也是找不到该对象的。这样就无法删除HashSet集合中的这个对象,因此导致内存泄漏。
3.机器的连接数和关闭时间设置
长时间开着非常耗费资源的连接也会造成内存泄漏。
四、内存溢出的几种情况:
1.方法区内存溢出(outOfMemoryError:permgem space)
在jvm规范中,方法区主要存放的是类信息、常量、静态变量等。
所以如果程序加载的类过多,或者使用反射、gclib等这种动态代理生成类的技术,就可能导致该区发生内存溢出,一般该区发生内存溢出时的错误信息为:
outOfMemoryError:permgem space
2.线程栈溢出(java.lang.StackOverflowError)
线程栈时线程独有的一块内存结构,所以线程栈发生问题必定是某个线程运行时产生的错误。
一般线程栈溢出是由于递归太深或方法调用层级过多导致的。
发生栈溢出的错误信息为:
java.lang.StackOverflowError
五、避免内存泄漏和内存溢出的几种方法:
1、尽早释放无用对象的引用
2、使用字符串处理,避免使用String,应大量使用StringBuffer,每一个String对象都得独立占用内存一块区域
3、尽量少用静态变量,因为静态变量存放在方法区,方法区基本不会被垃圾回收
4、避免在循环中创建对象
5、开启大型文件或从数据库一次拿了太多的数据很容易造成内存溢出,所以在这些地方要大概计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值。
以上是关于java 内存泄露问题的主要内容,如果未能解决你的问题,请参考以下文章