开发者社区 问答 正文

java读取160M的文件总是内存溢出,求大侠们帮忙看下代码是否有问题:报错

public static HashMap<String, String> ip2map = new HashMap<String, String>();
public static HashMap<String, ArrayList<String>> map2localtion = new HashMap<String, ArrayList<String>>();

	public UDFGetIPLocation() {
		//String uri ="hdfs://hd03:9000/user/hive/warehouse/ip_location/IP-COUNTRY-REGION-CITY.CSV.hive";
		String uri = "hdfs://localhost:9000/hadoop/test/IP-COUNTRY-REGION-CITY.CSV.hive";
		Configuration conf = new Configuration();
		FileSystem fs = null;
		FSDataInputStream in = null;
		BufferedReader d = null;

		try {
			fs = FileSystem.get(URI.create(uri), conf);
			in = fs.open(new Path(uri));
			d = new BufferedReader(new InputStreamReader(in));
			String s = null;
			int stat = 1;
			while (true) {
				System.out.println("line "+stat++);
				s = d.readLine();
				if (s == null) {
					break;
				} else {
					String[] parts = StringUtils.split(s, "\001");// 确认分割符
					if (!(parts[0].equals("-") || parts[1].equals("-") || parts[2].equals("-"))) {
						// set ip2map
						for (long start = Long.parseLong(parts[0]); start <= Long
								.parseLong(parts[0]) + 255; start++) {
							ip2map.put(Long.toString(start), parts[0]);
						}
						// set map2localtion
						map2localtion.put(parts[0], new ArrayList<String>());
						for (int i = 0; i < parts.length; i++) {
							map2localtion.get(parts[0]).add(parts[i]);
						}
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			IOUtils.closeStream(in);
		}
	}

刚刚出炉的一个类,其实是写的hive的UDF。读取一个160M左右的文件,但是总是在读到9500行左右的时候报内存溢出。求大侠指导,3Q

展开
收起
kun坤 2020-06-07 16:36:08 810 分享 版权
1 条回答
写回答
取消 提交回答
  • 上数据库吧,大概扫了一下你的代码,map2localtion、ip2map中存放的东西太多了,肯定需要很多内存。

    如果不上数据库的话可以考虑以下措施:

    1、使用-Xmx参数,给虚拟机更配更大的内存,这是个治标不治本的方法,多试几次就能试出来到底应该分多大了。

    2、IBM developer works上面有个关于String性能优化的文章,很适合你的程序,建议你仔细看看,借鉴优化一下StringUtils.split()之后的流程。 

    ######回复 @六只 : String.split()正则确实有点慢,不过楼主这里是遇到了内存不释放的问题。假如一个10000长度的字符串,split以后里面有用的只有10字符,我把这10个字符强引用了,那么这10字符就会占用10000字符的内存不释放,很恐怖######String自身的split效率确实不怎么样,之前做过分析和对比,可以作为参考。http://www.congmo.net/blog/2012/02/13/1/######谢谢建议,我再优化一下试试,3Q ^ ^######大文件不推荐一次性读取######…建议拆分字符串那里 直接用Pattern和Matcher类 不要拆了######

    引用来自“liuex”的答案

    上数据库吧,大概扫了一下你的代码,map2localtion、ip2map中存放的东西太多了,肯定需要很多内存。

    如果不上数据库的话可以考虑以下措施:

    1、使用-Xmx参数,给虚拟机更配更大的内存,这是个治标不治本的方法,多试几次就能试出来到底应该分多大了。

    2、IBM developer works上面有个关于String性能优化的文章,很适合你的程序,建议你仔细看看,借鉴优化一下StringUtils.split()之后的流程。 

    谢谢各位了。试了一下String的优化(分别用StringTokenizer和Pattern),效率确实有了提升,但是还是在读到13000行左右开始内存溢出。后来用了其它的办法:把2个map都去掉了,用了一个List<String>把csv文件中的所有行读到List中,然后定义2个String[] ,分别保存起始IP和结束IP,之后做了一个二分查找,直接定位了需要查找的IP所在List的索引,然后再Split 。这样就没有内存溢出了。

    再次感谢各位!

     

    2020-06-08 11:17:02
    赞同 展开评论