程序流程:
从数据库中把数据分页查询出来.
再把数据用dom4j组成xml.
最后转成byte数组用socket发送.如果数据库中数据有二进制数据的话.byte数组则会很大.这里用base64编码.比原来的还要大些.而且是多线程的频繁操作.
程序跑了一会就Game Over了.   OutOfMemoryError 不知道有什么好办法来解决这个问题?我想到的是一个是加大VM的内存设置.但这个总是不能解决根本办法吧.
java程序内存好象只增不减.而且对于一下要开辟大内存的byte数组很容易就挂了.先谢过..

解决方案 »

  1.   

    用JRunner或jprofile测试一下,OutOfMemoryError 是内存溢出错误你这个错误看看能否用队列的方式处理来解决,然后看看内存是否释放或者用nio的客户端,不需要频繁的建立Socket,降低内存损耗
      

  2.   

    这是一个Nio客户端的测试package NioTest;
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.ByteBuffer;
    import java.nio.CharBuffer;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;
    import java.nio.charset.Charset;
    import java.nio.charset.CharsetDecoder;
    import java.util.Iterator;
    import java.util.Set;public class NioEchoServer { private static Selector roller = null; private static final int port = 5000; private static NioEchoServer instance = null; private ThreadLocal<StringBuffer> stringLocal = new ThreadLocal<StringBuffer>(); private NioEchoServer() throws IOException {
    ServerSocketChannel serverChannel = ServerSocketChannel.open();
    serverChannel.socket().bind(new InetSocketAddress(port));
    serverChannel.configureBlocking(false);
    serverChannel.register(roller, SelectionKey.OP_ACCEPT);
    } public synchronized static NioEchoServer getInstance() throws IOException {
    if (instance == null) {
    roller = Selector.open();
    instance = new NioEchoServer();
    }
    return instance;
    } public void start() throws IOException {
    int keyAdded = 0;
    while ((keyAdded = roller.select()) > 0) {
    Set<SelectionKey> keySets = roller.selectedKeys();
    Iterator iter = keySets.iterator();
    while (iter.hasNext()) {
    SelectionKey key = (SelectionKey) iter.next();
    iter.remove();
    actionHandler(key);
    }
    }
    } public void actionHandler(SelectionKey key) throws IOException {
    if (key.isAcceptable()) {
    ServerSocketChannel serverChannel = (ServerSocketChannel) key
    .channel();
    SocketChannel socketChannel = serverChannel.accept();
    socketChannel.configureBlocking(false);
    socketChannel.register(roller, SelectionKey.OP_READ);
    } else if (key.isReadable()) {
    ByteBuffer buffer = ByteBuffer.allocate(16);
    SocketChannel socketChannel = (SocketChannel) key.channel();
    socketChannel.read(buffer);
    buffer.flip();
    String temp = decode(buffer);
    StringBuffer strBuffer = stringLocal.get();
    if (strBuffer == null) {
    strBuffer = new StringBuffer();
    } strBuffer.append(temp); //if (temp.equals("\r\n")) {
    System.out.println(strBuffer.toString());
    strBuffer = null;
    //}
    stringLocal.set(strBuffer);
    }
    } public String decode(ByteBuffer buffer) {
    Charset charset = null;
    CharsetDecoder decoder = null;
    CharBuffer charBuffer = null;
    try {
    charset = Charset.forName("UTF-8");
    decoder = charset.newDecoder();
    charBuffer = decoder.decode(buffer);
    return charBuffer.toString();
    } catch (Exception ex) {
    ex.printStackTrace();
    return "";
    }
    } public static void main(String[] args) {
    try {
    NioEchoServer.getInstance().start();
    } catch (IOException e) {
    // TODO Auto-generated catch block  
    e.printStackTrace();
    }
    }
    }
      

  3.   

    不好意思,这个才是客户端,上面的是服务端
    package NioTest;import java.io.IOException;
    import java.net.*;
    import java.nio.ByteBuffer;
    import java.nio.channels.*;
    import java.util.Iterator;
    import java.util.Set;public class Client { private static final String EXIT = "EXIT"; private InetAddress host;
    private int port; public Client(InetAddress host, int port) {
    this.host = host;
    this.port = port;
    } public void startClient() throws IOException {
    // 创建SocketChannel
    SocketChannel channel = SocketChannel.open(new InetSocketAddress(host,
    port));
    channel.configureBlocking(false); // 创建Selector
    Selector selector = Selector.open();
    // 向Selector注册我们需要的READ事件
    SelectionKey skey = channel.register(selector, SelectionKey.OP_WRITE);
    boolean stop = false;
    int n = 0;
    int read = 0;
    ByteBuffer buffer = ByteBuffer.allocate(1024); System.out.println("Client Start"); // 轮询
    while (!stop) {
    // 获取Selector返回的时间值
    n = selector.select(); // 当传回的值大于0事,读时间发生了
    if (n > 0) {
    Set set = selector.selectedKeys();
    Iterator it = set.iterator(); while (it.hasNext()) {
    skey = (SelectionKey) it.next();
    it.remove(); if (skey.isReadable()) {
    SocketChannel sc = (SocketChannel) skey.channel(); while ((read = sc.read(buffer)) != -1) {
    if (read == 0)
    break;
    buffer.flip();
    byte[] array = new byte[read];
    buffer.get(array);
    String s = new String(array);
    System.out.print(s);
    buffer.clear(); if (s.endsWith(EXIT)) {
    stop = true;
    System.out.println();
    }
    }
    }
    }
    }
    } channel.close();
    System.out.println("Client Stop");
    } public static void main(String[] args) throws Exception {
    Client client = new Client(InetAddress.getLocalHost(), 5000);
    client.startClient();
    }

    private ByteBuffer sendBuffer = ByteBuffer.allocate(1024);
    }
      

  4.   

    尽量用非阻塞流操作和非阻塞套接字还有你解析的xml有多大? 频繁解析过大的xml也容易内存溢出,如果xml太大的话,可以考虑转为string用正则
      

  5.   

    1. 先看下是不是哪儿有死循环的bug,
    2. dom4j本身解析耗用的内存就比较大,大概是1:10
    3. 把虚拟机内存改大一些:-Xms512m -Xmx1024m
      

  6.   

    能否不用base64编码,我曾经做过测试,base64编码会把文件内容加大很多,可以采取其他的方式压缩一下肯看效果
      

  7.   

    没有一个说到问题的本质,如果数据本身有1G,内存只有512K,上面那些砖家你给我弄看看.处理大数据量的原则就是即时处理,不能把所有数据准备好一下子转换,简单说读一点输出一点.1G的数据,每读54个字节base64编码成76个字符.然后输出一次,比如电子邮件的附件发送,
    先把附件之前的文本输出,然后把文件读一点,编码一点,输出一点,然后再把后面的文档输出.这问题本身和NIO没有任何关系.因为它是内存中存储不了大的数据,不知道为什么要有扯到NIO.
      

  8.   

    比如
    <xml>
    <otherfiled>value</otherfiled>
    <binfile></binfile>
    <otherfiled></otherfiled>输出<xml>
    <otherfiled>value</otherfiled>
    <binfile>
    然后数据库中的二进制对象,从inputStream每读byte[59],编码,输出,完成后再输出></binfile>
    <otherfiled></otherfiled>
    这样有处理10M内存就足够了.以前486上一般有8M内存就不错了,处理几百兆的文件还不是一样.
      

  9.   

    我已经用Optimizeit分析过了.不存在没有释放的资源.
    关于socket方面.我这是建的长连接.每3M为分包点发一个包.
    我觉的问题关键不在这能否不用base64编码..老板要求xml格式必须符合soap格式.本来想用MIME附件形式的.但还是没有被通过.关于建个缓冲的byte流的办法我也想过.但不是很好做.可能我技术还没达到.
    程序要求是把数据库里的数据组成xml包以socket发送.
    从blob中读取用一点一点的读.但最终还是要以dom树的形式放到内存中!
    接着把dom树转成byte数组.一个具大的byte数组.10M左右.
    总不能xml组一半发一次.再组一半发一次吧.
    而且还是多线程并发处理.不知道如何是好.byte[] btRet = null;
    btRet = document.asXML().getBytes();
      

  10.   

    怎么可能呢.即使一定要生成dom树,但对blob字段那里不生成就行了.或者用一个固定的字符串替换去.
    byte[] rt = new byte[9];假如它编码后的Base64字符串为: Xyzf65D9xcvf
    你从数据库读到blob后先不要把blob编码进去,直接用rt这个byte代替,放到dom树中,最后dom树生成后,
    得到一个XML文本,然后找到Xyzf65D9xcvf前的内容先输出去,再读blob编一点输出一点,再把Xyzf65D9xcvf后的内容输出去.
    如果觉得生成dom树时,如果不读blog,数据库连结太久,就先把它读到一个临时文件中,dom树生成后再从这个临时文件中读取.这手多线程没有任何关系.