我需要使用Struts2
和Freemarker
将数据转储为大型xml(50~500 Mb):
<?xml version="1.0" encoding="UTF-8"?>
<documents>
<#list collection as document>
<document>
...
</document>
<#if document_index % 100 == 0>
<#flush/>
</#if>
</#list>
</document>
由于collection
可能很大,它已经实现了一个内部逻辑来获取部分数据,只要有可用的数据就消耗它并再次获取。
问题似乎与XML的缓冲区有关:偶尔应用程序崩溃(java.lang.OutOfMemoryError
)。
每100个文档调用一个Freemarker flush
,但我不知道是否实际发生了刷新,根据documentation它只是嵌入软件的指示({{1} }} + Strut2
)。
有关如何强行冲洗的任何建议吗?
JVM处理大约1~2 Gb的堆内存,可能只是内存问题?
为此目的,可以正确调整Tomcat7
吗?
答案 0 :(得分:1)
在此用例中不需要调用#flush
。当缓存Writer
(或其背后的OutputStream
)以进行性能时,缓冲区的大小限制相当低(十几千字节等),之后它将自动刷新。如果输出由于某些功能原因而被缓冲,例如,为了确保输出可以在任何时候完全回滚,或者输出可以作为单个String
返回,那么你应该修复无论如何(那也是#flush
可能被忽略的地方)。因此,尝试在freemarker.template.Template.createProcessingEnvironment
上设置一个断点并检查调试器中的out
Writer
参数(以及Writer
/ OutputStream
Writer
写入等等)。也许某处会有StringWriter
。
答案 1 :(得分:1)
我找到了解决方案。
问题在于Struts2 FreemarkerResult
以及这个类如何让你处理输出编写器的刷新。
基本上,如果您使用TemplateExceptionHandler.RETHROW_HANDLER
作为异常处理程序(就像我一样),则在执行任何刷新之前处理整个模板。 (这是所需的行为,因为如果存在任何模板错误,您希望在将任何输出发送到响应之前抛出并处理更高级别的异常)
但是TemplateExceptionHandler
是FreemarkerManager
中嵌入的固定配置,无法根据给定请求的需要进行切换。
我决定扩展FreemarkerResult
重写方法doExecute(...)
以包含一个参数,该参数强制执行单个请求的标准 flushing-during-template-process ,即使全局配置为TemplateExceptionHandler.RETHROW_HANDLER
。