Problem wydajnościowy (zużycie pamięci)

0

Witam wszystkich forumowiczów,
Załączam kod testowej klasy, która jest wycinkiem mojego programu do przetwarzania obrazów.

Problem mam taki, że wczytuję tam wielokrotnie duże ilości obrazów, czasem np. ok. 300. Każdy ma rozdzielczość 512x512px;

Każdy piksel obrazu opisuję klasą Point. Tak więc dla każdego obrazu tworzę 512x512 obiektów typu Point, które przechowuję w tablicy Point[][].

Następnie każdy z tych obrazów przechowuję w kolekcji ArrayList<Point[][]>. Czyli kolekcja zawierać może ok. 300 takich tablic.

W przesłanej klasie imituję zachowanie mojego programu podczas wczytywania danych.

W klasie Test jest zmienna 'count', która mówi o ilości "obrazów".

Przy małej liczbie (<100) wszystko jakoś działa, ale przy większej liczbie zawsze wywali Java Heap Space przy ogólnej liczbie pamięci ponad 1GB!

Oto mój testowy kod:

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Scanner;

public class ObjectPerformanceTest {
	public static void main(String[] args) {
		Test test = new Test();
	}
}

class Test {
	
	public Test() {
		int count = 20; //INCREASE THIS VALUE (e.g. 200) AND OBSERVE MEMORY USAGE
		
		test1(count);
		System.out.println("-------------");
		test2(count);
		
		Scanner scanner = new Scanner(System.in);
		scanner.nextLine();
	}
	
	private void test1(int count) {
		float time = 0.0F;
		
		time = performCreateByNewTest(count);
		
		System.out.println("New object consuming: " + time + " sec");
		displayMemory();
	}
	
	private void test2(int count) {
		try {
			float time = 0.0F;
			
			time = performCreateByCloneTest(count);
			
			System.out.println("Clone object consuming: " + time + " sec");
			displayMemory();
		} catch (CloneNotSupportedException e) {
			
		}
	}

	private float performCreateByNewTest(int count) {
		long start = System.currentTimeMillis();
		
		ArrayList<Point[][]> pointsArr = new ArrayList<Point[][]>();
		for (int c = 0; c < count; c++) {
			Point[][] points = new Point[512][512];
			
			for (int i = 0; i < 512; i++)
				for (int j = 0; j < 512; j++) {
					Point p = new Point(i, j);
					p.setIntensity(1000);
					points[i][j] = p;
				}
			
			pointsArr.add(points);
		}
		
		long elapsedTimeMillis = System.currentTimeMillis()-start;
		return elapsedTimeMillis/1000F;
	}
	
	private float performCreateByCloneTest(int count) throws CloneNotSupportedException {
		long start = System.currentTimeMillis();
		
		ArrayList<Point[][]> pointsArr = new ArrayList<Point[][]>();
		for (int c = 0; c < count; c++) {
			Point[][] points = new Point[512][512];
			
			for (int i = 0; i < 512; i++)
				for (int j = 0; j < 512; j++) {
					Point p = createPointObject();
					p.setX(i);
					p.setY(j);
					p.setIntensity(1000);
					points[i][j] = p;
				}
			
			pointsArr.add(points);
		}
		
		long elapsedTimeMillis = System.currentTimeMillis()-start;
		return elapsedTimeMillis/1000F;
	}
	
	Hashtable<String, Point> _cacheTemplate = new Hashtable<String, Point>();
	public Point createPointObject() throws CloneNotSupportedException {
		Point p = (Point) _cacheTemplate.get( "Point" );
		if (p == null) {
			p = new Point();
			_cacheTemplate.put( "Point", p );
		}
		return (Point) p.clone();
	}
	
	public void displayMemory() {
		int mb = 1024*1024;
	    Runtime r = freeMemory();
	    System.out.println("Total memory: " + (double)r.totalMemory()/mb + " MB");
	    System.out.println("Free memory: " + (double)r.freeMemory()/mb + " MB");
	    System.out.println("Memory Used="+(double)(r.totalMemory()-r.freeMemory())/mb + " MB");
	}
	
	public Runtime freeMemory() {
		Runtime r = Runtime.getRuntime();
	    r.gc();
	    r.gc();
	    return r;
	}
	
}

class Point implements Cloneable, Comparable<Point> {
	private int x = 0;
	private int y = 0;
	private int intensity = 0;
	
	public Point() {}
	
	public Point(int x, int y) {
		this.x = x;
		this.y = y;
	}
	
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}
	public int getIntensity() {
		return intensity;
	}
	public void setIntensity(int intensity) {
		this.intensity = intensity;
	}
	
	public void increase(int val){
		this.intensity = this.intensity + val;
	}
	
	@Override
	public String toString() {
		return "("+x+", "+y+") = "+intensity;
	}
	
	public Object clone() throws CloneNotSupportedException {
		Object obj = super.clone();
		return obj;
    }
	
	public int compareTo(Point p) {
		return this.getIntensity() - p.getIntensity();
	}
}

Bardzo proszę o podpowiedzi, jak ten problem rozwiązać.

Będę wdzięczny za wszelkie odpowiedzi.

Pozdrawiam.

0

512 px/ linię * 512 linii/ obrazek * 300 obrazków * 24 bajty/ px (12 bajtów zmienne + 8 bajtów narzutu na obiekt + wyrównanie do 8 bajtów) ~~ 1.76 GiB.

Po co ci tu w ogóle klasa Point? A konkretnie po co ci pola x i y, skoro trzymasz punkty w tablicy i masz od razu ich współrzędne?

1

Programowanie nie polega na bezmyślnym klepaniu kodu... albo włącz myślenie, albo daj sobie z tym spokój. Taka moja rada.

0

Ano ciężko widzę to. Też kiedyś byłem początkującym i też robiłem przetwarzanie obrazu (w sekwencji miałem o wiele więcej niż 300 -500), ale na takie coś to bym w życiu nie wpadł. Wywal tą klasę Point bo ona jest Ci do d potrzebna. Skup się na wielowymiarowych tablicach. Ja jeszcze miałem każdy obraz budowany na nieregularnej piramidzie także w ogóle u mnie te tablice były "postrzępione" by tylko mniej pamięci żarło.

Taki przykład z głowy. Masz nr obrazka jego x i y i jeszcze 2 parametry dla tego piksela.

[nr obrazka][x][y][par 1][par 2];

0

Kerai - post który zamieściłeś jest zupełnie bezwartościowy.

Wibowit, Lipkerson,
Macie rację, jeżeli chodzi o tablice wielowymiarowe. Takie rozwiązanie stosowałem w poprzednich aplikacjach.
Dla lepszego zobrazowania problemu, powiem, że obrazy pochodzą z rezonansu lub tomografu komputerowego.
Celem zmiany podejścia na typowo obiektowe jest próba przeniesienia przestrzeni trójwymiarowej wyznaczonej przez te obrazy na strukturę drzewa ósemkowego lub szesnastkowego. To pozwoli mi przenieść wykonywane obliczenia na voxelach obrazu na kartę graficzną. Dodatkowo będzie możliwa wizualizacja trójwymiarowa tych danych z wykorzystaniem biblioteki OpenGL.

Dziękuję Wam bardzo za odpowiedzi, jeżeli ktoś ma jeszcze jakiś pomysł to zapraszam do dalszej dyskusji.

0

Szesnastkowe? Zdjęcia są czterowymiarowe? A może symulujesz czasoprzestrzeń? Nieważne w sumie. Dalej nie napisałeś po co ci pola x i y w klasie Point.

To ci się może przydać: http://volumeviewer.kenai.com/

0
lipkerson napisał(a)

[...]jego x i y i jeszcze 2 parametry dla tego piksela.
[nr obrazka][x][y][par 1][par 2];

jest tylko intensity, stawiałbym na "float obrazki [300][512][512]".
float nie int

a, że uczy się C++ zamiast C, wpycha bzdurne przykłady klasowości, straszy analizą złożoności zamiast dać jakieś wyczucie (choćby prosty rachunek Wibowita)
to już zupełnie inna historia

0

Obiektowo to nie znaczy, że budujesz obiekt, który będzie przechowywał kopię danych, które już gdzieś istnieją i są dostępne. Zrób sobie obiekt, który sięga do danych leżących w oryginalnych miejscach. Przydzielaj pamięć w nowych obiektach tylko na nowe dane, które wynikają z rzeczywistego przetwarzania informacji (kopiowanie nie jest takim przetwarzaniem) - a problem pamięci zniknie Ci jak od rąbnięcia różdżką. :)
Nie musisz też trzymać danych obiektowo - możesz zupełnie "prymitywnie". Grunt, żeby obiektowo dało się obrabiać skoro tak potrzebujesz.
Koledzy już to napisali, choć nieco inaczej.

0

mctommek piszesz ten doft w/dla Alteris w K-CE?

1 użytkowników online, w tym zalogowanych: 0, gości: 1