在Java中,从数据库写入(zip)文件的内存效率最高的方法是什么?

在Java中,从数据库写入(zip)文件的内存效率最高的方法是什么?,java,file,optimization,memory,writer,Java,File,Optimization,Memory,Writer,我的程序已经足够快了,但我宁愿放弃这个速度进行内存优化,因为一个用户的最大内存使用量高达300 MB,这意味着他们中很少有人会经常使应用程序崩溃。我找到的大多数答案都与速度优化有关,而其他答案只是一般性的(“如果您直接从数据库写入内存,那么应该不会有太多内存使用”)。嗯,似乎有:)我在考虑不发布代码,这样我就不会“锁定”某人的想法,但另一方面,如果你看不到我已经做了什么,我可能是在浪费你的时间,所以这里是: // First I get the data from the database in

我的程序已经足够快了,但我宁愿放弃这个速度进行内存优化,因为一个用户的最大内存使用量高达300 MB,这意味着他们中很少有人会经常使应用程序崩溃。我找到的大多数答案都与速度优化有关,而其他答案只是一般性的(“如果您直接从数据库写入内存,那么应该不会有太多内存使用”)。嗯,似乎有:)我在考虑不发布代码,这样我就不会“锁定”某人的想法,但另一方面,如果你看不到我已经做了什么,我可能是在浪费你的时间,所以这里是:

// First I get the data from the database in a way that I think can't be more 
// optimized since i've done some testing and it seems to me that the problem 
// isn't in the RS and setting FetchSize and/or direction does not help.

public static void generateAndWriteXML(String query, String oznaka, BufferedOutputStream bos, Connection conn)
        throws Exception
{
    ResultSet rs = null;
    Statement stmt = null;
    try
    {
        stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        rs = stmt.executeQuery(query);
        writeToZip(rs, oznaka, bos);
    } finally
    {
        ConnectionManager.close(rs, stmt, conn);
    }
}

// then I open up my streams. In the next method I'll generate an XML from the
// ResultSet and I want that XML to be saved in an XML, but since its size takes up
// to 300MB, I want it to be saved in a ZIP. I'm thinking that maybe by writing 
// first to file, then to zip I could get a slower but more efficient program.

private static void writeToZip(ResultSet rs, String oznaka, BufferedOutputStream bos)
        throws SAXException, SQLException, IOException
{
    ZipEntry ze = new ZipEntry(oznaka + ".xml");
    ZipOutputStream zos = new ZipOutputStream(bos);
    zos.putNextEntry(ze);
    OutputStreamWriter writer = new OutputStreamWriter(zos, "UTF8");
    writeXMLToWriter(rs, writer);
    try
    {
        writer.close();
    } catch (IOException e)
    {
    }
    try
    {
        zos.closeEntry();
    } catch (IOException e)
    {
    }
    try
    {
        zos.flush();
    } catch (IOException e)
    {
    }
    try
    {
        bos.close();
    } catch (IOException e)
    {
    }
}

// And finally, the method that does the actual generating and writing. 
// This is the second point I think I could do the memory optimization since the
// DataWriter is custom and it extends a custom XMLWriter that extends the standard
// org.xml.sax.helpers.XMLFilterImpl I've tried with flushing at points in program,
// but the memory that is occupied remains the same, it only takes longer.

public static void writeXMLToWriter(ResultSet rs, Writer writer) throws SAXException, SQLException, IOException
{
    //Set up XML
    DataWriter w = new DataWriter(writer);
    w.startDocument();
    w.setIndentStep(2);
    w.startElement(startingXMLElement);
    // Get the metadata
    ResultSetMetaData meta = rs.getMetaData();
    int count = meta.getColumnCount();
    // Iterate over the set
    while (rs.next())
    {
        w.startElement(rowElement);
        for (int i = 0; i < count; i++)
        {
            Object ob = rs.getObject(i + 1);
            if (rs.wasNull())
            {
                ob = null;
            }
            // XML elements are repeated so they could benefit from caching
            String colName = meta.getColumnLabel(i + 1).intern();
            if (ob != null)
            {
                if (ob instanceof Timestamp)
                {
                    w.dataElement(colName, Util.formatDate((Timestamp) ob, dateFormat));
                }
                else if (ob instanceof BigDecimal)
                {
                    // Possible benefit from writing ints as strings and interning them
                    w.dataElement(colName, Util.transformToHTML(new Integer(((BigDecimal) ob).intValue())));
                }
                else
                {   // there's enough of data that's repeated to validate the use of interning
                    w.dataElement(colName, ob.toString().intern());
                }

            }
            else
            {
                w.emptyElement(colName);
            }
        }
        w.endElement(rowElement);
    }
    w.endElement(startingXMLElement);
    w.endDocument();
}
//首先,我从数据库中获取数据的方式是我认为再简单不过的了
//优化,因为我已经做了一些测试,它似乎对我来说,这个问题
//不在RS中,设置FetchSize和/或direction没有帮助。
公共静态void generateAndWriteXML(字符串查询、字符串oznaka、BufferedOutputStream bos、连接连接)
抛出异常
{
结果集rs=null;
语句stmt=null;
尝试
{
stmt=conn.createStatement(ResultSet.TYPE\u SCROLL\u不敏感,ResultSet.CONCUR\u只读);
rs=stmt.executeQuery(查询);
writeToZip(rs、oznaka、bos);
}最后
{
连接管理器关闭(rs、stmt、conn);
}
}
//然后我打开我的小溪。在下一个方法中,我将从
//ResultSet和我希望将XML保存在XML中,但由于它的大小占用了
//到300MB,我希望它保存在一个ZIP中。我在想也许通过写作
//首先是文件,然后是zip,我可以得到一个速度较慢但效率更高的程序。
私有静态void writeToZip(结果集rs、字符串oznaka、BufferedOutputStream bos)
抛出SAXException、SQLException、IOException
{
ZipEntry ze=新的ZipEntry(oznaka+“.xml”);
ZipoutStream zos=新ZipoutStream(bos);
佐斯·普特内森特里(泽);
OutputStreamWriter writer=新的OutputStreamWriter(zos,“UTF8”);
writeXMLToWriter(rs,writer);
尝试
{
writer.close();
}捕获(IOE异常)
{
}
尝试
{
zos.closeEntry();
}捕获(IOE异常)
{
}
尝试
{
zos.flush();
}捕获(IOE异常)
{
}
尝试
{
bos.close();
}捕获(IOE异常)
{
}
}
//最后,是实际生成和编写的方法。
//这是第二点,我认为我可以做内存优化,因为
//DataWriter是自定义的,它扩展了扩展标准的自定义XMLWriter
//org.xml.sax.helpers.XMLFilterImpl我在程序中尝试过刷新,
//但是占用的内存保持不变,只需要更长的时间。
公共静态void writeXMLToWriter(ResultSet rs,Writer-Writer)引发SAXException、SQLException、IOException
{
//设置XML
DataWriter w=新的DataWriter(writer);
w、 startDocument();
w、 步骤(2);
w、 startElement(startingXMLElement);
//获取元数据
ResultSetMetaData meta=rs.getMetaData();
int count=meta.getColumnCount();
//在集合上迭代
while(rs.next())
{
w、 startElement(rowElement);
for(int i=0;i
编辑:下面是一个内存使用示例(使用visualVM):

EDIT2:数据库是Oracle 10.2.0.4。我只设置了ResultSet.TYPE_FORWARD_,最大使用量为50MB!正如我在评论中所说的,我会关注这一点,但这确实是有希望的


EDIT3:似乎还有另一种可能的优化。正如我所说,我正在生成一个XML,这意味着大量的数据被重复(如果没有其他内容,那么是标记),这意味着String.intern()可以帮助我,我将在测试时发回。

由于它是Java,内存应该只会暂时增加,除非你泄漏引用,比如,如果你把事情推到一个列表上,这个列表是一个具有整个程序生命周期的单例的成员,或者根据我的经验,更可能是资源泄漏,当使用非托管资源(如文件句柄)的对象从不调用其清理代码时(我假设这适用于Java,尽管我想到的是C#),通常由空异常处理程序引起的一种情况,这些处理程序不会重新抛出到父堆栈帧,这具有绕过finally块的净效果…

是否可以仅使用ResultSet.TYPE\u FORWARD\u


您已使用ResultSet.TYPE\u SCROLL\u不敏感。我相信对于某些数据库(您没有说明使用哪一个),这会导致整个结果集加载到内存中。

我已经运行了一些测试,得出的结论是:

  • 最大的好处是JVM(或者visualvm在监视Java 5堆空间时遇到问题: