java内存溢出问题

java程序运行时,内存溢出了,会报错误:java.lang.OutOfMemoryError: Java heap space。
一些操作会持续消耗大量内存,通过设置JVM的内存大小不能从根本上解决内存溢出的问题。下面说两个我遇到的内存溢出问题和解决办法。

1. 集合对象元素过多

  • 背景:
    两个线程,线程A向一个队列里加入元素,线程B从同一个队列取出元素,写入的速度比取出的快,一段时间后内存溢出。
  • 问题定位:
    这种情况定位问题比较麻烦,因为内存不是一次性爆的,而是慢慢加到爆的。控制台打印出来的出错那一行可能只是赋值了一个对象, 而真正的错误原因是因为队列太大。所以要定位这类问题,需要特别关注一下集合对象放入和取出元素的操作。
  • 解决思路:
    控制集合大小不靠谱,既然是内存的问题,就要以内存作为控制条件。在每次向集合中插入新元素之前,判断集合是否超过某个阈值(如500M),如果超过,则让插入的线程休眠,等待另一线程取出集合中的元素,至集合大小低于某一阈值(如350M)后再继续插入。
  • 具体方案:
    主要解决计算对象占用内存大小的问题。可以把对象转为字节数组,再得到这个数组的大小。可以用对象流,也可以用Jackson-mapper这样的东西。

2. 单个结果集对象过大

  • 背景:
    在对数据库的操作中,有时需要获取一个很大的结果集,保存到ResultSet对象中。这个结果集如果比jvm设定的内存大,就会造成内存溢出。
  • 解决思路:
    对于mysql,JDBC的URL这样写:
    jdbc:mysql://localhost/:3306/test?useCursorFetch=true&
    defaultFetchSize=500

    主要是加上useCursorFetch和fetchsize和这两个参数。设置使用游标遍历数据和游标每次遍历的条数,这样就不会把结果集全部cache到内存里,就避免了内存溢出的问题。
    这样设置过后,程序没有内存溢出的错误了,但是会导致另外一个问题:响应慢,一段时间才有数据返回。
    这个问题可能的解释是,mysql要等游标遍历完成才开始返回数据。这样一来,传输数据的时候,迟迟看不到数据开始传,用户体验不好;另一方面,效率也较低,如果需要重启传输什么的,就更崩溃了。
    对于这个问题,在java中设置statement,用流的方式接受数据就可以解决:
    stmt = (com.mysql.jdbc.Statement) con.createStatement();
    stmt.enableStreamingResults();

    注意这是mysql才有的问题,enableStreamingResults也是mysql的JDBC才有的。
    对于其他数据库,我就不懂了….Oracle的话,据说默认不会把结果集cache到内存,一般不会有内存溢出的问题。而且Oracle有快速返回机制,可以马上返回已经获取到的结果。DB2和SQLServer就是一点都不懂了….
    放两篇参考的博客:
    http://soft.chinabyte.com/database/258/12609258.shtml
    http://blog.sina.com.cn/s/blog_670620330101n8dz.html
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值