Question

I'm building a back-up server that I can run on a remote computer. The problem now is that I have a memory leak, I think. When transferring large files, after a while the following error appears:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.lang.StringCoding$StringDecoder.decode(StringCoding.java:149)
    at java.lang.StringCoding.decode(StringCoding.java:193)
    at java.lang.StringCoding.decode(StringCoding.java:254)
    at java.lang.String.<init>(String.java:536)
    at java.lang.String.<init>(String.java:556)
    at Server.run(Server.java:61)
    at Server.main(Server.java:107)

I've read a quiet few of articles about this but none really gave me an answer to how to solve this. The code is down below. Thanks in advance.

Server:

private ServerSocket server;
private Socket acceptingSocket;

public Server(int port){
    try {
        server = new ServerSocket(port);
    } catch (IOException e) {
        System.out.println("Try again");
    }
}

/**
 * Reads all files and puts them in the back-up folder. Also creates the appropriate dirs.
 */
public void run(){
    BufferedInputStream buffer = null;
    DataInputStream reader = null;
    BufferedOutputStream out = null;
    DataOutputStream writer = null;
    int size = 0;
    try {
        acceptingSocket = server.accept();
        buffer = new BufferedInputStream(acceptingSocket.getInputStream());
        reader = new DataInputStream(buffer);
        out = new BufferedOutputStream(acceptingSocket.getOutputStream());
        writer = new DataOutputStream(out);
        size = reader.readInt();
    } catch (IOException e1) {
    }
    System.out.println("Size: " + size);
            //Variables I need later on, I thought this would help
    byte[] name;
    int fileNameLength = 0;
    long length=0;
    boolean dir  = false;
    int t = 0;
    String dirs = "";
    File direcs;
    File file;
    byte[] b;
    int bytes=0;
    for(int j = 0; j < size; j++){
        try {
            fileNameLength = reader.readInt();
            name = new byte[fileNameLength];
            reader.read(name, 0,fileNameLength);
            String path = new String(name);
            System.out.println("Path: " + path);
            length = reader.readLong();
            dir = reader.readBoolean();
            path = "/backup" + path;
            file = new File(path);
            if(!dir){
                t = file.getAbsolutePath().lastIndexOf("/");
                dirs = file.getAbsolutePath().substring(0, t);
                direcs = new File(dirs);
                System.out.println(direcs.mkdirs());
                FileOutputStream fos = new FileOutputStream(file);
                BufferedOutputStream bos = new BufferedOutputStream(fos);
                b = new byte[(int) length];
                bytes = reader.read(b, 0, (int)length);
                if(bytes != -1)
                    bos.write(b,0,(int)length);                 

                writer.writeUTF("File " + file.getAbsolutePath() + " is created!");
                writer.flush();
                bos.flush();
                fos.flush();
                bos.close();
                fos.close();
                out.flush();

            } else file.mkdirs();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    try {
        buffer.close();
        reader.close();
        out.close();
        writer.close();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

public static void main(String[] args){
    int port = Integer.parseInt(args[0]);
    Server server = new Server(port);
    while(true)
        server.run();
}

Client:

private DataInputStream serverToClient;
private Socket client;
private DataOutputStream clientToServer;
private String name;

public Client(String name, int port){
    try {
        client = new Socket(name, port);
        //receive response server
        serverToClient = new DataInputStream(client.getInputStream());
        //send message to server
        clientToServer = new DataOutputStream(client.getOutputStream());
        this.name = name;
    }
    catch (IOException e) {
    }
}

/**
 * Closes all connections
 */
public void stop(){

    try {
        client.close();
        serverToClient.close();
        clientToServer.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

/**
 * Sends all files and content of the files to the back-up server
 * @param filePath
 */
public void backUp(String filePath){
    ArrayList<File> files = new ArrayList<File>();
    boolean dir = false;
    long length = 0;
    byte[] buffer;
    try{
        listf(filePath, files, 0);
        System.out.println(files.toString());
        clientToServer.writeInt(files.size());

        for(File fi : files){
            dir = false;
            if(fi.isDirectory()) dir = true;
            clientToServer.writeInt(fi.getAbsolutePath().length());
            System.out.println(fi.getAbsolutePath().length());
            clientToServer.writeBytes(fi.getAbsolutePath());
            System.out.println(fi.getAbsolutePath());
            length = fi.length();
            clientToServer.writeLong(length);
            clientToServer.writeBoolean(dir);
            System.out.println("Dir? " + dir);
            System.out.println(length);
            if(!dir){
                FileInputStream fis = new FileInputStream(fi);
                BufferedInputStream bis = new BufferedInputStream(fis);

                buffer = new byte[(int)length];

                bis.read(buffer, 0, (int)length);
                clientToServer.write(buffer);
                System.out.println(serverToClient.readUTF());
                bis.close();
                fis.close();
                clientToServer.flush();
            }
        }

    } catch(IOException e){
        e.printStackTrace();
    }
}

/**
 * Get all files, folders and subfolders in the file specified by directoryName, recursively.
 * @param directoryName
 * @param files
 * @param size
 */
private void listf(String directoryName, ArrayList<File> files, int size) {
    File directory = new File(directoryName);
    size = files.size();
    if(size > 100){
        System.out.println(size);
        size += 100;
    }
    if(directory.isFile()) files.add(directory);
    else{
        File[] fList = directory.listFiles();
        for (File file : fList) {
            if(file.isDirectory() && file.listFiles().length == 0) files.add(file);
            else{
                if (file.isFile()) {
                    files.add(file);
                } else if (file.isDirectory()) {
                    listf(file.getAbsolutePath(), files, size);
                }
            }
        }
    }
}

public static void main(String[] args){
    String name = args[0];
    int port = Integer.parseInt(args[1]);
    System.out.println("Name: " + name + " Port: " + port);
    Client client = new Client(name, port);
    File file = new File(args[2]);
    if(file.exists())client.backUp(args[2]);
    else System.out.println("File doesn't exist");
    client.stop();

}
Était-ce utile?

La solution

You don't need a buffer the size of the file. This just wastes memory and adds latency, and obviously it doesn't scale to large files. See this answer for the correct way to copy streams.

If you need to keep the socket open after the transfer, you need to know the length beforehand, and you need to modify the loop condition to

while (total < length && (count = in.read(buffer, 0, length-total > buffer.length ? buffer.length : (int)(length-total))) > 0)

where 'length' is the known file length, 'total' is initially zero. You must also increment 'total' by 'count' inside the loop.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top