0

I have been writing an updater for my game.

  1. It checks a .version file on drop box and compares it to the local .version file.

  2. If there is any link missing from the local version of the file, it downloads the required link one by one.

This is the error that it shows

Exception in thread "Thread-9" java.lang.OutOfMemoryError: Java heap space
at com.fox.listeners.ButtonListener.readFile(ButtonListener.java:209)
at com.fox.listeners.ButtonListener.readFile(ButtonListener.java:204)
at com.fox.listeners.ButtonListener.UpdateStart(ButtonListener.java:132)
at com.fox.listeners.ButtonListener$1.run(ButtonListener.java:58)

It only shows for some computers though and not all of them this is the readFile method

private byte[] readFile(URL u) throws IOException {
    return readFile(u, getFileSize(u));
}

private static byte[] readFile(URL u, int size) throws IOException {
    byte[] data = new byte[size];
    int index = 0, read = 0;
    try {
        HttpURLConnection conn = null;
        conn = (HttpURLConnection) u.openConnection();
        conn.addRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");
        InputStream is = conn.getInputStream();
        progress_a = 0;
        progress_b = data.length;
        while(index < data.length) {
            read = is.read(data, index, size-index);
            index += read;
            progress_a = index;
        }
    } catch(Exception e) {
        e.printStackTrace();
    }

    return data;
}

private byte[] readFile(File f) {
    byte[] data = null;
    try {
        data = new byte[(int)f.length()];

        @SuppressWarnings("resource")
        DataInputStream dis = new DataInputStream(new FileInputStream(f));
        dis.readFully(data);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return data;
}

This is the main method that is ran

public void UpdateStart() {
    System.out.println("Starting Updater..");

    if(new File(cache_dir).exists() == false) {
        System.out.print("Creating cache dir.. ");
        while(new File(cache_dir).mkdir() == false);
        System.out.println("Done");
    }


    try {
        version_live = new Version(new URL(version_file_live));
    } catch(MalformedURLException e) {
        e.printStackTrace();
    }

    version_local = new Version(new File(version_file_local));

    Version updates = version_live.differences(version_local);

    System.out.println("Updated");

    int i = 1;
    try {
        byte[] b = null, data = null;
        FileOutputStream fos = null;
        BufferedWriter bw = null;


        for(String s : updates.files) {
            if(s.equals(""))
                continue;


            System.out.println("Reading file "+s);
            AppFrame.pbar.setString("Downloading file "+ i + " of "+updates.files.size());
            if(progress_b > 0) {
                s = s + " " +(progress_a * 1000L / progress_b / 10.0)+"%";
            }

            b = readFile(new URL(s));



            progress_a = 0;
            progress_b = b.length;

            AppFrame.pbar.setString("Unzipping file "+ i++ +" of "+updates.files.size());

            ZipInputStream zipStream = new ZipInputStream(new ByteArrayInputStream(b));
            File f = null, parent = null;
            ZipEntry entry = null;
            int read = 0, entry_read = 0;
            long entry_size = 0;
            progress_b = 0;

            while((entry = zipStream.getNextEntry()) != null)
                progress_b += entry.getSize();

            zipStream = new ZipInputStream(new ByteArrayInputStream(b));

            while((entry = zipStream.getNextEntry()) != null) {
                f = new File(cache_dir+entry.getName());
                if(entry.isDirectory())
                    continue;

                System.out.println("Making file "+f.toString());

                parent = f.getParentFile();
                if(parent != null && !parent.exists()) {
                    System.out.println("Trying to create directory "+parent.getAbsolutePath());
                    while(parent.mkdirs() == false);
                }

                entry_read = 0;
                entry_size = entry.getSize();
                data = new byte[1024];
                fos = new FileOutputStream(f);

                while(entry_read < entry_size) {
                    read = zipStream.read(data, 0, (int)Math.min(1024, entry_size-entry_read));
                    entry_read += read;
                    progress_a += read;
                    fos.write(data, 0, read);
                }
                fos.close();
            }

            bw = new BufferedWriter(new FileWriter(new File(version_file_local), true));
            bw.write(s);
            bw.newLine();
            bw.close();
        }
    } catch(Exception e) {
        e.printStackTrace();
        return;
    }

    System.out.println(version_live);
    System.out.println(version_local);
    System.out.println(updates);
    CacheUpdated = true;
    if(CacheUpdated) {
        AppFrame.pbar.setString("All Files are downloaded click Launch to play!");
    }

}

I don't get why it is working for some of my players and then some of my other players it does not i have been trying to fix this all day and i am just so stumped at this point but this seems like its the only big issue left for me to fix.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • Is there something you don't understand about the error message? – Kayaman Oct 25 '15 at 14:38
  • @kayaman no what I don't understand is the fixing it issue – user2574211 Oct 25 '15 at 14:49
  • please provide information on how you launched the above code, i.e., which JVM parameters can be assumed here!? – MWiesner Oct 25 '15 at 15:04
  • Have you tried anything before asking this question on SO? – Kayaman Oct 25 '15 at 15:05
  • @MWiesner im just jarring it and running with no JVM Prams and im using 1.8 jdk to compile – user2574211 Oct 25 '15 at 15:12
  • You're loading an entire file into memory, in a byte array. The exception indicates that you don't have enough memory. How big is the file? – Wyzard Oct 25 '15 at 15:39
  • Have a look at this one: http://stackoverflow.com/questions/31390793/cannot-download-file-from-url-in-java/33252453#33252453 – Ravindra babu Oct 25 '15 at 16:42
  • What are you doing after reading data? If you are writing to a file, read file in chunks of byte array and write data in same chunks. You don't get OutOfMemory in that case. http://stackoverflow.com/questions/31390793/cannot-download-file-from-url-in-java/33252453#33252453 and one more question: http://stackoverflow.com/questions/18508836/java-outofmemoryerror-in-reading-a-large-text-file/31724120#31724120 – Ravindra babu Oct 25 '15 at 16:47

2 Answers2

0

Either increase the memory allocated to your JVM (How can I increase the JVM memory?), or make sure that the file being loaded in memory isn't gigantic (if it is, you'll need to find an alternate solution, or just read chunks of it at a time instead of loading the entire thing in memory).

Community
  • 1
  • 1
AdeelMufti
  • 341
  • 1
  • 8
0

Do your update in several steps. Here's some pseudo-code with Java 8. It's way shorter than what you wrote because Java has a lot of built-in tools that you re-write much less efficiently.

// Download
Path zipDestination = Paths.get(...);
try (InputStream  in = source.openStream()) {
  Files.copy(in, zipDestination);
}

// Unzip
try (ZipFile zipFile = new ZipFile(zipDestination.toFile())) {
  for (ZipEntry e: Collections.list(zipFile.entries())) {
    Path entryDestination = Paths.get(...);
    Files.copy(zipFile.getInputStream(e), entryDestination);
  }
}

// Done.
Olivier Grégoire
  • 33,839
  • 23
  • 96
  • 137