Защо получавам изключение за java heap space, когато зареждам около 11k изображения с размер около 40mb

Имам ситуация в моята програма, в която трябва да получа достъп до определен брой изображения, записани на моя твърд диск. Бих могъл или да ги заредя само след като наистина имам нужда от тях, или да ги заредя всички вече при стартиране.

От любопитство се опитах да прочета всички (около 11k) изображения от няколко папки и да ги запазя в няколко списъка. Чудех се дали това отнема твърде много време, но получих OutOfMemoryError след прочитане на около ~ 9k изображения.

Моят JRE има размер на купчината от 1g (-Xmx1g).

Защо това се случва с моя код? Произвеждам ли изтичане на памет? Имате ли някакви предложения какво да променя, за да не изпитвам повече това или решението е просто да чета само файловете, след като ми потрябват? Общият размер на всички файлове е само около 40mb, така че си помислих, че ще е добре да го запазя в паметта си (40mb изглежда не е твърде много от моя размер на купчината от 1g). Или java изпълнява някакви луди магически неща, умножавайки размера на файла с големи числа, след като бъде зареден?

Направих някои изследвания на stackoverflow, но не можах наистина да конвертирам дадените отговори (като от тук или тук) за моя случай. Така че, ако някой от вас има идея, ще се радвам наистина :)

Моят код е тук, съжалявам, ако е малко грозен - просто се бърках:

import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

public class FatfontsManager {

    private List<BufferedImage> until9;
    private List<BufferedImage> until99;
    private List<BufferedImage> until999;
    private List<BufferedImage> until9999;

    // loads and keeps all images 

    public FatfontsManager() {

        until9 = new ArrayList<>();
        until99 = new ArrayList<>();
        until999 = new ArrayList<>();
        until9999 = new ArrayList<>();

        String absolutPathToThisProject = new java.io.File("")
                .getAbsolutePath();

        // load Images
        for (int i = 1; i < 10; i++) {
            until9.add(loadImage(absolutPathToThisProject
                    + "\\latexDir\\0..9\\" + i + ".png"));
        }
        System.out.println("1 - 9 loaded");
        for (int i = 1; i < 100; i++) {
            until99.add(loadImage(absolutPathToThisProject
                    + "\\latexDir\\0..99\\" + i + ".png"));
        }
        System.out.println("1 - 99 loaded");
        for (int i = 1; i < 1000; i++) {
            until999.add(loadImage(absolutPathToThisProject
                    + "\\latexDir\\0..999\\" + i + ".png"));
        }
        System.out.println("1 - 999 loaded");
        for (int i = 1; i < 10000; i++) {
            until9999.add(loadImage(absolutPathToThisProject
                    + "\\latexDir\\0..9999\\" + i + ".png"));
        }
        System.out.println("1 - 9999 loaded");
    }

    public static void main(String[] args) {
        new FatfontsManager();
    }

    public static BufferedImage loadImage(String ref) {
        BufferedImage bimg = null;
        try {

            bimg = ImageIO.read(new File(ref));
        } catch (Exception e) {
            System.err.println("Error loading image file " + ref);
            e.printStackTrace();
        }
        return bimg;
    }

}

Благодаря много за всеки отговор.


person Waylander    schedule 14.07.2013    source източник


Отговори (1)


Общият размер на всички файлове е само около 40mb ...

Но когато заредите файловете с изображения в паметта, изображенията ще бъдат декомпресирани и превърнати в масиви от пиксели. В зависимост от оригиналния файлов формат на изображението (и параметрите за компресиране) това може да изисква порядък или повече пространство в стек.

Не е съвсем ясно какво се опитвате да постигнете, но може би трябва да помислите само за кеширане на тези изображения в паметта, когато те действително ще бъдат използвани.

person Stephen C    schedule 14.07.2013
comment
Да, мисля, че тогава ще кеширам само онези моменти, които всъщност ми трябват. Просто бях объркан, че толкова много памет се губи. Изображенията са в .png, само черно-бели и нямат голяма височина/широчина. Но ако ви разбирам правилно, когато казвам, че се декомпресират - няма значение дали съдържат прозрачни области или само черно-бели пиксели. Благодаря много за отговора! - person Waylander; 14.07.2013