内存溢出(Memory Overflow)和内存泄露(Memory Leak)的区别
内存溢出:指你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数据,就是溢出。
内存泄漏:指申请了一块内存,使用过后没有将内存释放,导致这块内存一直处于占用状态。内存泄漏的堆积最终会导致内存溢出。
一、内存溢出
指程序在申请内存时,没有足够的内存供申请者使用,举例:给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,就会导致内存不够用,报错OOM,即出现内存溢出的错误。
溢出原因:
1、内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
2、集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
3、代码中存在死循环或循环产生过多重复的对象实体;
4、使用的第三方软件中的BUG;
5、启动参数内存值设定的过小
溢出的解决方案:
第一步,修改JVM启动参数,直接增加内存(-Xms、-Xmx参数)。
第二步,检查错误日志,查看“OutOfMemory”错误前是否有其 它异常或错误。
第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。
二、内存泄露
内存泄露是指程序中间动态分配了内存,但在程序结束时没有释放这部分内存,从而造成那部分内存不可用的情况,重启计算机可以解决,但也有可能再次发生内存泄露,内存泄露和硬件没有关系,它是由软件设计缺陷引起的。
从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。
内存泄漏产生的4种方式:
1、常发性内存泄漏:发生泄漏的代码会被多次执行到,每次被执行时都会导致一块内存泄漏。
2、偶发性内存泄漏:发生泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。
3、一次性内存泄漏:发生泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块且仅有一块内存发生泄漏。
4、隐式内存泄漏:程序在过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。
举例:你租了个带钥匙的柜子,存完东西之后把柜子锁上,把钥匙丢了或者没有将钥匙还回去,那么结果就是这个柜子将无法供给任何人使用,也无法被垃圾回收器回收,因为找不到他的任何信息。
三、常见问题
内存溢出即用户在对其数据缓冲区操作时,超过了其缓冲区的边界;尤其是对缓冲区写操作时,缓冲区的溢出很可能导致程序的异常。
1、内存溢出类型
(1)java.lang.OutOfMemoryError:PermGen space
PermGen space 全称是(Permanent Generation space)是指内存的永久保存区域。这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGenspace中,它和存放类实例(Instance)的堆(Heap)区域不同,GC不会在主程序运行期对PermGenspace进行清理。
JVM由XX:PermSize设置非堆内存初始值,默认是物理内存的1/64。
JVM由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。
错误常见场合:
应用中有很多Class,web服务器对Java编译时。
app使用了大量的第三方jar,其大小超过了JVM默认的大小 4M 时。
(2)java.lang.OutOfMemoryError:Java heap space
在JVM中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息。
JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;
JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。
JVM内存的最大值跟操作系统有很大的关系。32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了。
注意:如果Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。
错误常见场合:
Web上传文件时。
开启大型文件或从数据库中一次取了太多的数据。
2、如何检测内存泄露?
可以通过一些性能监测分析工具,如 JProfiler、OptimizeitProfiler。
3、如何避免内存泄露、溢出?
1、尽早释放无用对象的引用。好的办法是使用临时变量的时候,让引用变量在退出活动域后自动设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄露。
2、程序进行字符串处理时,尽量避免使用String,而应使用StringBuffer。
3、尽量少用静态变量,因为静态变量是全局的,GC不会回收。
4、避免集中创建对象尤其是大对象,如果可以的话尽量使用流操作。JVM会突然需要大量内存,这时会触发GC优化系统内存环境。
5、尽量运用对象池技术以提高系统性能。生命周期长的对象拥有生命周期短的对象时容易引发内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。
不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。可以适当的使用hashtable,vector创建一组对象容器,然后从容器中去取那些对象,而不用每次new之后又丢弃。
4、内存溢出的解决方案?
(1)一是从代码层面进行优化完善,尽量避免该情况发生;
(2)二是调整优化服务器配置:
设置-Xms、-Xmx相等;
设置NewSize、MaxNewSize相等;
设置Heap size, PermGen space:
参考文章
Java代码写出StackOverflowError和OutOfMemoryError溢出异常:http://www.ibloger.net/article/2311.html
https://www.cnblogs.com/meidang/p/7594083.html
未经允许请勿转载:程序喵 » 内存溢出(Memory Overflow)和内存泄露(Memory Leak)的区别