java.lang.OutOfMemoryError: Java heap space 堆内存异常

spring 专栏收录该内容
14 篇文章 0 订阅

java.lang.OutOfMemoryError: Java heap space 堆内存异常,不得不说,bug真是程序员的好朋友,通过这一周的学习,我学习了堆内存溢出的原因,解决方案,如何调整jar包的内存大小等等等等。

/**
 * 数值预报
 * 
 * @author gaoyongqin
 *
 */
public class SzybDB {
 
    public static void intoDB(File inFile) {
        // 经度,纬度,温度,过去一小时降水
        // Lat,Lon,TEM,PRE_1h
        PreparedStatement prep = null;
        Connection con = C3P0Inner.getConnection();
        String foreignKeySql = "insert into data_szyb values";
        StringBuilder foreignKeyValue = new StringBuilder();
 
        int i = 0;
        String str = null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH");
        BufferedReader br = null;
        String format = sdf.format(new Date());
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(inFile)));
            while ((str = br.readLine()) != null) {
                i++;
                // 该文件第一行直接就是数据,所以不用过滤掉表头
                foreignKeyValue.append(",").append("(").append("null").append(",'");
                String replace = str.replace(" ", "','");
                String name = inFile.getName();
                foreignKeyValue.append(replace).append("','").append(name.substring(0, name.indexOf(".")));
                foreignKeyValue.append("','").append(format).append("')");
                if (i % 5000 == 0) {
                    try {
                        foreignKeyValue.deleteCharAt(0);
                        prep = con.prepareStatement(foreignKeySql + foreignKeyValue.toString()
                                + "ON DUPLICATE KEY UPDATE TEM=VALUES(TEM),PRE_1h=VALUES(PRE_1h)"
                                + ",updateTime=VALUES(updateTime)");
                        prep.executeUpdate();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    } 
                    foreignKeyValue = new StringBuilder();
                }
            }
            if (foreignKeyValue != null && !"".equals(foreignKeyValue)) {
                try {
                    foreignKeyValue.deleteCharAt(0);
                    prep = con.prepareStatement(foreignKeySql + foreignKeyValue.toString()
                            + "ON DUPLICATE KEY UPDATE TEM=VALUES(TEM),PRE_1h=VALUES(PRE_1h)"
                            + ",updateTime=VALUES(updateTime)");
                    prep.executeUpdate();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                System.out.println("数值预报数据在  :" + sdf.format(new Date()) + " 时,入库成功");
            } else {
                System.out.println("数值预报数据在  :" + sdf.format(new Date()) + " 时,无数据");
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
 
            try {
                if (br != null) {
                    br.close();
                }
                if (prep != null) {
                    prep.close();
                }
                if (con != null) {
                    con.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
丝毫不夸张,我找了我代码的原因找了一周,甚至于我一度认为我的代码没有任何的问题,肯定是jar包进程的内存开的不够大,我还请教了磊哥。迪哥,喜喜。磊哥还教我如何使用jmap等工具

nohup java -Djava.library.path=/home/qht/jdk1.7.0_79/jre/bin -Xms4096m -Xmx4096m -XX:+UseG1GC -jar pythonListen.jar zdyb &>log.log &
/home/qht/jdk1.7.0_79/bin/jmap -heap 30869
/home/qht/jdk1.7.0_79/bin/jmap -histo:live 30869
 

我调整了运行jar包的进程内存大小,自己得意的不行,安全的跑了一天的数据,第二天悲催的又堆内存溢出了,这下我不淡定了。感情没几天就要去内蒙部署项目了,现在还在这崩着呢!其中除了内存溢出,还有一个错误:

Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
 
The last packet successfully received from the server was 59,977 milliseconds ago.  The last packet sent successfully to the server was 1 milliseconds ago.
链接超时了,我压根儿没把这两个错误联系在一起,这为我后面找了这个bug找了两周埋下了伏笔。讲真的,我又学会了如何去处理这个链接超时:

参考:https://www.cnblogs.com/chrischennx/p/7279215.html?utm_source=itdadao&utm_medium=referral

第一种:调节wait_timeout,

设置mysql超时:
mysql -uroot -p -h 127.0.0.1

set  global  interactive_timeout=31536000;
set  global  wait_timeout=31536000;

将wait_timeout设置成一年。

第二种:

为了避免空闲时间过长超过最大空闲时间而被断开,我们设置三个配置:

validationQuery: SELECT 1
testWhileIdle: true
timeBetweenEvictionRunsMillis: 28000
其中timeBetweenEvictionRunsMillis需要小于mysql的wait_timeout。

但是这种方法无法避免重启的情况,不过一般数据库不会频繁重启,影响不大,如果非得频繁重启,可以通过设置testOnBorrow,即申请连接的时候先试一试连接是否可用,不过带来的影响就是性能降低,需要根据实际需求合理取舍。

其中因为我是用的c3p0链接的数据库,所以设置的参数有点不一样,但是想法是一样的。

参考:https://blog.csdn.net/mmake1994/article/details/86561940

 

好了,后面再说一下那个内存溢出吧!!!

后面其实我想通了,为什么内存溢出了,然后就是链接超时了,哦~~~~(你应该了解我的心情。)

那大约就应该是链接没有关闭???抱着这样的想法,我改了我的代码!

/**
 * 数值预报
 * 
 * @author gaoyongqin
 *
 */
public class SzybDB {
 
    public static void intoDB(File inFile) {
        // 经度,纬度,温度,过去一小时降水
        // Lat,Lon,TEM,PRE_1h
        PreparedStatement prep = null;
        Connection con = C3P0Inner.getConnection();
        String foreignKeySql = "insert into data_szyb values";
        StringBuilder foreignKeyValue = new StringBuilder();
 
        int i = 0;
        String str = null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH");
        BufferedReader br = null;
        String format = sdf.format(new Date());
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(inFile)));
            while ((str = br.readLine()) != null) {
                i++;
                // 该文件第一行直接就是数据,所以不用过滤掉表头
                foreignKeyValue.append(",").append("(").append("null").append(",'");
                String replace = str.replace(" ", "','");
                String name = inFile.getName();
                foreignKeyValue.append(replace).append("','").append(name.substring(0, name.indexOf(".")));
                foreignKeyValue.append("','").append(format).append("')");
                if (i % 5000 == 0) {
                    try {
                        foreignKeyValue.deleteCharAt(0);
                        prep = con.prepareStatement(foreignKeySql + foreignKeyValue.toString()
                                + "ON DUPLICATE KEY UPDATE TEM=VALUES(TEM),PRE_1h=VALUES(PRE_1h)"
                                + ",updateTime=VALUES(updateTime)");
                        prep.executeUpdate();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            if (prep != null) {
                                prep.close();
                            }
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                    foreignKeyValue = new StringBuilder();
                }
            }
            if (foreignKeyValue != null && !"".equals(foreignKeyValue)) {
                try {
                    foreignKeyValue.deleteCharAt(0);
                    prep = con.prepareStatement(foreignKeySql + foreignKeyValue.toString()
                            + "ON DUPLICATE KEY UPDATE TEM=VALUES(TEM),PRE_1h=VALUES(PRE_1h)"
                            + ",updateTime=VALUES(updateTime)");
                    prep.executeUpdate();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                System.out.println("数值预报数据在  :" + sdf.format(new Date()) + " 时,入库成功");
            } else {
                System.out.println("数值预报数据在  :" + sdf.format(new Date()) + " 时,无数据");
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
 
            try {
                if (br != null) {
                    br.close();
                }
                if (prep != null) {
                    prep.close();
                }
                if (con != null) {
                    con.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
仔细对比代码,没错,我在每一次链接完数据库之后都会在finally里把prep链接关闭。然后结合着jmap查看,果然,正如我所料。

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:终极编程指南 设计师:CSDN官方博客 返回首页

打赏作者

stone_tomcat

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值