内存泄漏和内存溢出

内存泄漏memory leak :
指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但 内存泄漏堆积后的后果就是内存溢出
JVM 虚拟机是使用引用计数法和可达性分析来判断对象是否可回收,本质是判断一个对象是否还被引用,如果没有引用则回收。在开发的过程中,由于代码的实现不同就会出现很多种内存泄漏问题,让gc 系统误以为此对象还在引用中,无法回收,造成内存泄漏。
静态集合类,如HashMap、LinkedList等等。如果这些容器为静态的,那么它们的生命周期与程序一致,则容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。简单而言,长生命周期的对象持有短生命周期对象的引用,尽管短生命周期的对象不再使用,但是因为长生命周期对象持有它的引用而导致不能被回收。
各种连接,如数据库连接、网络连接和IO连接等。在对数据库进行操作的过程中,首先需要建立与数据库的连接,当不再使用时,需要调用close方法来释放与数据库的连接。只有连接被关闭后,垃圾回收器才会回收对应的对象。否则,如果在访问数据库的过程中,对Connection、Statement或ResultSet不显性地关闭,将会造成大量的对象无法被回收,从而引起内存泄漏。

变量不合理的作用域。一般而言,一个变量的定义的作用范围大于其使用范围,很有可能会造成内存泄漏。另一方面,如果没有及时地把对象设置为null,很有可能导致内存泄漏的发生。

 

public class UsingRandom {

		private String msg;

		public void receiveMsg(){
		
		readFromNet();// 从网络中接受数据保存到msg中
		
		saveDB();// 把msg保存到数据库中

}

}

通过readFromNet方法把接受的消息保存在变量msg中,然后调用saveDB方法把msg的内容保存到数据库中,此时msg已经就没用了,由于msg的生命周期与对象的生命周期相同,此时msg还不能回收,因此造成了内存泄漏。

实际上这个msg变量可以放在receiveMsg方法内部,当方法使用完,那么msg的生命周期也就结束,此时就可以回收了。还有一种方法,在使用完msg后,把msg设置为null,这样垃圾回收器也会回收msg的内存空间。

(泄漏的原因本质上是长期存活对象引用短期存活对象,导致短期存活对象占用的对象无法回收。)??需要论证

内存泄漏的解决办法

1.尽量减少使用静态变量,或者使用完及时 赋值为 null。

2.明确内存对象的有效作用域,尽量缩小对象的作用域,能用局部变量处理的不用成员变量,因为局部变量弹栈会自动回收;

3.减少长生命周期的对象持有短生命周期的引用;

4.使用StringBuilder和StringBuffer进行字符串连接,Sting和StringBuilder以及StringBuffer等都可以代表字符串,其中String字符串代表的是不可变的字符串,后两者表示可变的字符串。如果使用多个String对象进行字符串连接运算,在运行时可能产生大量临时字符串,这些字符串会保存在内存中从而导致程序性能下降。

5.对于不需要使用的对象手动设置null值,不管GC何时会开始清理,我们都应及时的将无用的对象标记为可被清理的对象;

6.各种连接(数据库连接,网络连接,IO连接)操作,务必显示调用close关闭。

内存问题排查

没有任何一个程序员想要出现这种问题,但是出现了问题也要解决,内存泄漏的主要表象就是内存不足,内存告警之后如何判断是否有内存泄漏。

第一步 首先确认逻辑问题,

查看内存中对象的数量和大小,判断是否在合理的范围,如果在合理的范围内,增大内存配置,调整内存比例就可以了。

命令:jmap -heap pid

第二步:分析gc是否正常执行

命令:

jstat -gcutil <pid> 1000

第三步 确认下版本新增代码的改动,尽快从代码上找出问题。

第四步:开启各种命令行和 导出 dump 各种工具分析

     推荐使用jprofile 进行本地分析(JProfiler是由ej-technologies GmbH公司开发的一款性能瓶颈分析工具)

内存溢出 out of memory :
     
(1)指程序申请内存时, 没有足够的内存供申请者使用
(2)给了一块存储int类型数据的存储空间,但是却存储long类型的数据,结果就是 内存不够用,此时就会报错OOM,即所谓的内存溢出。
内存溢出的原因
引起内存溢出的原因有很多种,常见的有以下几种:
  • 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
  • 代码中存在死循环或循环产生过多重复的对象实体;
  • 使用的第三方软件中的BUG;
  • 启动参数内存值设定的过小
解决方案:
第一步,修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)
-Xms :堆初始大小 -Xmx :堆最大值
第二步,检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。
第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。
       重点排查以下几点:
  • 1.检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
  • 2.检查代码中是否有死循环或递归调用。
  • 3.检查是否有大循环重复产生新对象实体。
  • 4.检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。
第四步,使用内存查看工具动态查看内存使用情况
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值