当前位置: 首页 > article >正文

JAVA解析XML时的内存消耗问题

问题出现

最近一个项目中,有个需求功能是从外部传入的XML读取数据,然后写入到数据库中。
写完之后,有在本地电脑上的Tomcat跑了一下,正常读取到XML中的数据,并整理好后,插入了数据库保存了。但是线上运行的时候,经常会出现因为这个功能而导致Tomcat直接闪退的问题。

一开始以为是线上环境,外部传入的XML文件数量比较多,在读取XML文件列表的时候有问题,因为用的是递归方法在多层目录中查找所有XML文件,后面发现,目录层次不深,递归不应该出问题。

之后在本地电脑上搞了几百个XML文件(每个7MB左右)做测试,还是能正常读取完并且写入数据库。有一轮测试的时候,不小心看了一下本地电脑的内存使用情况,发现运行过程中,内存使用从7.8G一路涨到了9.4G,之后一直平稳保持到运行结束,又降回7.8G。

这时候,问题就很明显了,读取XML文件的过程消耗内存太严重,线上Tomcat的总堆内存才1GB,肯定是撑不住的。

这引起了我的好奇心,这里一个XML也才7MB,读取的时候到底能消耗多少内存?

于是打开了JV(jdk/bin目录下jvisualvm.exe)。给程序读取XML文件的地方打上断点,监测结果如下:
读取XML文件前
读取到XML文件后
发现了Eden Space(新生代空间)最大空间340M(为了和线上环境一样,本地电脑的Tomcat总堆内存也被我设置为1GB了,按Tomcat默认规则Eden空间就是1/3大小),读取一个XML文件直接就用了150M,占用Eden内存达到了190M,再来一个直接到满了,所以只要GC释放稍慢一点,直接就跑不动了(我本地电脑GC快,所以还是能正常跑完,就是GC次数比较多)

之后,查了下资料,发现我用的dom读取法,是比较占用内存的,但是这个方法能修改XML内容(不过我这个需求功能不需要),另外的SAX比较不耗内存。
在这里插入图片描述

于是就换了下XML的读取方式,终于是让线上的Tomcat(堆内存1GB)也能正常读取完大量XML文件了。下面是2种方法,在本地读取1000个XML的监测结果,GC次数差了一倍:
dom方式读取XML,GC次数
sax方式读取XML,GC次数

下面来说下,改后的读取方式使用,用的是JAVA自带的JAXBContext(javax.xml.bind.JAXBContext)
1、首先需要一个和XML结构相同的对象,如果是多层节点的,就需要对象引用对象了。

@XmlRootElement(name = "ROOT") //注解法指定根元素/对象与元素绑定,大小写需要一致;也可以换设置法
public static class Root{
	BookVo bookVo; //java对象中的属性名可以和节点名不一致
	public BookVo getBookEle() { //对象必做有get/set,且需要和XML节点名对应,<ROOT><bookEle>...</bookEle></ROOT>
		return viosurveilVo;
	}
	public void setBookEle(BookVo bookVo) {
		this.viosurveilVo = viosurveilVo;
	}
}
public static BookVo{...}
//解析指定xml文件
private Root analysisXML(String xmlFilePath) {
	try {
		JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
		Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
		StreamSource source = new StreamSource(new File(xmlFilePath));
		JAXBElement<Root> jaxbElement = unmarshaller.unmarshal(source, Root.class); //指定法,指定根元素/对象与元素绑定
		Root root = jaxbElement.getValue(); //直接得到可操作JAVA对象
		//Root root = (Root) unmarshaller.unmarshal(new File(xmlFilePath)); //使用@注解法,只需要这句,不需要上面3句
		//ViosurveilVo viosurveilVo = root.getViosurveil();
		return root;
	}catch (Exception e) {
		return null;
	}
}

http://www.kler.cn/news/10118.html

相关文章:

  • IronOCR for .NET crack,IronOCR的独特功能
  • CMake入门教程【核心篇】8.0构建目标
  • 2023-03-18青少年软件编程(C语言)等级考试试卷(一级)解析
  • 是时候告别这些 Python 库了
  • 你真的会用background属性?
  • 【51单片机Task】:led十六进制控制led灯详解、按键控制流水灯、跑马灯等任务
  • x210官方uboot配置编译
  • DNS服务器配置
  • 机器学习和深度学习在气象中的应用(台风预报只能订正、风速预报订正、LSTM 方法预测 ENSO)
  • 基于Spring boot和Vue3的博客平台:系统通知、评论回复通知、专栏更新通知、用户角色与权限管理模块
  • 数据技术嘉年华星光璀璨,云和恩墨全栈数据技术能力闪耀会场
  • Vue实现自动化平台(五)--用例编辑页面
  • ​InnoDB引擎之flush脏页​
  • 大数据4 - 分布式计算
  • 电话机器人开发
  • c++学习之c++对c的扩展2
  • Zebec Protocol 出席香港 Web3 峰会,带来了哪些信息?
  • ROS开发之如何制作launch启动文件?
  • windows服务器自带IIS搭建网站并发布公网访问【内网穿透】
  • 怎么恢复永久删除的文件
  • vscode中的配置
  • ARM与C语言的混合编程【嵌入式系统】
  • STC89C52定时器的简介
  • Shader 海面/水面
  • 一次弄懂gzip模块启用和配置指令
  • TypeScript类成员的存取器
  • 《八次危机》速读笔记
  • 【ROS2指南-1】配置ROS2环境
  • 机器学习实战:Python基于K近邻KNN进行分类预测(四)
  • 【举一反三】只出现一次的数字