说说 Java内存溢出与内存泄漏

分析&回答


堆内存溢出(OutOfMemoryError: Java heap space)

内存溢出是指程序运行过程中申请的内存大于系统能够提供的内存,导致无法申请到足够的内存,于是就发生了内存溢出。

会导致 JVM 内存溢出的一些场景:

  • JVM 启动参数堆内存值设定的过小
  • 内存中加载的数据量过于庞大(一次性从 Mysql、Redis 取出过多数据)
  • 对象的引用没有及时释放,使得JVM不能回收
  • 代码中存在死循环或循环产生过多重复的对象实体

方法区内存溢出(outOfMemoryError:permgem space)

加载的类过多,或者使用反射、gclib等这种动态代理生成类的技术,就可能导致该区发生内存溢出(1.8之前)

线程栈溢出(java.lang.StackOverflowError)

  • 线程栈时线程独有的一块内存结构,所以线程栈发生问题必定是某个线程运行时产生的错误
  • 线程栈溢出是由于递归太深或方法调用层级过多导致的

内存泄漏(Memory Leak)

内存泄漏是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。

会导致 Java 内存泄漏的一些场景:

  • 长生命周期的对象持有短生命周期对象的引用
  • 过度使用静态成员属性(static fields)
  • 忘记关闭已打开的资源链接(unclosed Resources)
  • 没有正确的重写 equals 和 hashcode 方法。(HashMap HashSet)当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段,否则对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中删除当前对象,造成内存泄露。

开发时的编码建议

  • 尽早释放无用对象的引用
  • 尽量少用静态变量,因为静态变量存放在永久代(方法区),永久代基本不参与垃圾回收(1.8之前)
  • 避免在循环中创建对象
  • 使用字符串处理,避免使用String,应大量使用StringBuffer,每一个String对象都得独立占用内存一块区域
  • 开启大型文件或从数据库一次拿了太多的数据很容易造成内存溢出,所以在这些地方要大概计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值。

反思&扩展


内存溢出问题一般分为两种:

  • 一种是由于大峰值下瞬间创建大量对象而导致的内存溢出;
  • 一种是由于内存泄漏而导致的内存溢出。
    第一种问题可通过限流来处理,第二种问题需要分析程序是否存在 Bug

喵呜面试助手: 一站式解决面试问题,你可以搜索微信小程序 [喵呜面试助手] 或关注 [喵呜刷题] -> 面试助手 免费刷题。如有好的面试知识或技巧期待您的共享!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喵呜刷题

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值