内存泄漏和内存溢出

1.内存泄漏

内存泄漏指的是一个不再被程序使用的对象或则变量依旧在内存中占有空间。
判断一个内存空间是否符合垃圾回收的标准有两点:第一,对象赋予了null值,以后再也没有被使用。第二,给对象赋予了新值,重新分配了内存空间。内存泄漏主要有两种情况:一是堆申请的空间没有被释放掉;而是对象不再使用,依然还在内存中保留。垃圾回收机制可以有限处理第一种情况,而对第二种情况,无法保证不再使用的对象会被释放

造成内存泄漏的原因:

①静态集合类:例如HashMap ,如果这些容器是静态的,由于他们的生命周期与程序一致,那么容器中的对象在程序结束前不能被释放,从而造成内存泄漏。
②各种连接,如数据库连接,IO连接。当不再使用时候需要close方法来释放与数据库的连接。只有连接关闭后,垃圾回收器才会回收对应的对象。
③变量不合理的作用域。如果一个变量定义的作用范围大于其使用范围,很有可能造成内存泄漏;另一方面如果没有及时把对象设置为null,很有可能导致内存泄漏的发生。
④单例模式可能会造成内存泄漏。

内存泄露的解决方案

1、 尽量少用静态变量, 因为静态变量存放在永久代(方法区) , 永久代基本不参与垃圾回收。
2、 避免在循环中创建对象。
3、 尽早释放无用对象的引用。 (最基本的建议)
4、 使用字符串处理, 避免使用 String, 应大量使用 StringBuffer, 每一个 String对象都得独立占用内存一块区域。

2.内存溢出

指程序运行过程中无法申请到足够的内存而导致的一种错误。

内存溢出的几种情况(OOM 异常):

OutOfMemoryError 异常
除了程 序计数器外 , 虚拟机内 存的其他几 个运行时区 域都有发生
OutOfMemoryError(OOM)异常的可能。

1.虚拟机栈和本地方法栈溢出
如 果 线 程 请 求 的 栈 深 度 大 于 虚 拟 机 所 允 许 的 最 大 深 度 , 将 抛 出StackOverflowError 异常。
如 果 虚 拟 机 在 扩 展 栈 时 无 法 申 请 到 足 够 的 内 存 空 间 , 则 抛 出OutOfMemoryError 异常。

2.堆 溢出一般的异常信息: java.lang.OutOfMemoryError:Java heap spaces。出现这种异常, 一般手段是先通过内存映像分析工具(如 Eclipse MemoryAnalyzer)对 dump 出来的堆转存快照进行分析, 重点是确认内存中的对象是否是必要的, 先分清是因为内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。

3.方法区溢出
异常信息: java.lang.OutOfMemoryError:PermGen space。

4.运行时常量池溢出
异常信息: java.lang.OutOfMemoryError:PermGen space。

导致内存溢出的原因:

1.内存中加载的数据量过于庞大, 如一次从数据库取出过多数据;
2.代码中存在死循环或循环产生过多重复的对象实体;
3.集合类中有对对象的引用, 使用完后未清空, 使得 JVM 不能回收;
4.启动参数内存值设定的过小。

内存溢出的解决方法

第一步, 修改 JVM 启动参数, 直接增加内存。 (-Xms, -Xmx 参数一定不要忘记加。一般要将-Xms 和-Xmx 选项设置为相同, 以避免在每次 GC 后调整堆的大小; 建议堆的最大值设置为可用内存的最大值的 80%)。

第二步, 检查错误日志, 查看“OutOfMemory” 错误前是否有其它异常或错误。

第三步, 对代码进行走查和分析, 找出可能发生内存溢出的位置。

3.如何减少 gc 出现的次数(java 内存管理)

(1)对象不用时最好显式置为 Null
一般而言,为 Null 的对象都会被作为垃圾处理,所以将不用的对象显式地设
为 Null,有利于 GC 收集器判定垃圾,从而提高了 GC 的效率

(2)尽量少用 System.gc()
此函数建议 JVM进行主 GC,虽然只是建议而非一定,但很多情况下它会触发
主 GC,从而增加主 GC 的频率,也即增加了间歇性停顿的次数。

(3)尽量少用静态变量
静态变量属于全局变量,不会被 GC 回收,它们会一直占用内存。

(4) 尽量使用 StringBuffer,而不用 String 来累加字符串。
由于 String 是固定长的字符串对象,累加 String 对象时,并非在一个 String
对象中扩增,而是重新创建新的 String 对象,如 Str5=Str1+Str2+Str3+Str4,这条语句执行过程中会产生多个垃圾对象,因为对次作“+”操作时都必须创建新的 String 对象,但这些过渡对象对系统来说是没有实际意义的,只会增加更多的垃圾。 避免这种情况可以改用 StringBuffer 来累加字符串,因 StringBuffer是可变长的,它在原有基础上进行扩增,不会产生中间对象。

(5)分散对象创建或删除的时间
集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内
存,JVM 在面临这种情况时,只能进行主 GC,以回收内存或整合内存碎片,从
而增加主 GC 的频率。
集中删除对象,道理也是一样的。 它使得突然出现了大量的垃圾对象,空
闲空间必然减少,从而大大增加了下一次创建新对象时强制主 GC 的机会。

(6) 尽量少用 finalize 函数。 因为它会加大 GC 的工作量, 因此尽量少用finalize 方式回收资源。

(7)能用基本类型如 int,long,就不用 Integer,Long 对象
基本类型变量占用的内存资源比相应包装类对象占用的少得多,如果没
有必要,最好使用基本变量。

(8) 增大-Xmx 的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值