核心解法是采用流式解析(SAX 或 StAX)避免全量加载,内存占用稳定;SAX 基于回调、轻量只读,需拼接 characters;StAX 为拉模式更灵活,支持按需读取;预处理可先分块再解析;还需禁用 DTD、关闭命名空间感知、及时清理缓存。

XML 文件太大导致内存不足,核心解法是避免一次性加载整个文档到内存,改用流式解析(SAX 或 StAX),边读边处理,内存占用 稳定在常量级。
用 SAX 解析:轻量、只读、事件驱动
SAX(Simple API for XML)是基于回调的推模式解析器,不构建 DOM 树,适合只读、顺序处理大 XML。Java 中用 red”>org.xml.sax 包即可,无需额外依赖。
- 注册
ContentHandler,重写startElement、characters、endElement等方法 - 遇到目标标签(如
<item></item>)才提取数据,其余跳过 - 注意:
characters()可能被多次调用,需用StringBuilder拼接文本内容
用 StAX 解析:拉模式,更灵活可控
StAX(Streaming API for XML)是 Java 内置的拉模式解析器(javax.xml.stream),比 SAX 更直观,支持跳过无关节点、部分回退(有限)、按需读取。
- 用
XMLInputFactory创建XMLStreamReader - 循环调用
next()或nextTag(),用getEventType()判断当前是 START_ELEMENT、CHARACTERS 还是 END_ELEMENT - 遇到
START_ELEMENT时检查getLocalName(),匹配后读子元素或属性,处理完立即丢弃引用
预处理 + 分块:先切再解析
若原始 XML 结构规整(如大量同级 <record></record> 包裹数据),可先用流式方式按行 / 标签边界分割成小文件或片段,再逐个解析。
- 用
BufferedReader逐行扫描,检测<record></record>和边界,累积为字符串片段 - 每凑齐一个完整记录,用
StringReader喂给轻量 DOM 或 StAX 解析——仅该记录进内存 - 适合需要随机访问字段、或后续要转 JSON/ 数据库插入的场景
补充建议:减少开销 & 避坑
即使流式解析,细节不当也会隐式吃内存:
- 禁用 DTD 和外部实体(防止 XXE),设置
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true) - 关闭命名空间感知(如不需要):
factory.setNamespaceAware(false),提升速度 - 不要在 handler 里长期缓存节点内容;用完即清,尤其
characters返回的 char[]别直接保存 - 大文件建议配合
InputStream而非File,便于加 gzip 解压(如 XML 是。gz 压缩的)
基本上就这些。流式不是万能,但对 GB 级 XML,SAX/StAX 是可靠选择;关键在“不建树、不回溯、不缓存”,逻辑清晰了,内存压力自然下来。