[RESOLVIDO]OutofMemory BitMap

14 respostas
danilorangelmg

E ai pessoal tudo beleza!

estou tendo um problema serio, estou fazendo download via aplicação de um numero considerável de imagens tipo umas 5000 imagens de varias dimensões todas. eu começo a baixar tá tudo tranquilo, quando eu chego em torno da imagem 1800 eu estouro o heap size do aparelho. pesquisando pela nela testei algumas soluções e vi na documentação do Android falando do Option implementando o inSampleSize, porem essa variavel diminui o tamanho da imagem, como estou usando Bitmap, já chamei o recycle(), já chamei o system.gc(), chamei os dois juntos tb, e não consigo achar uma forma de limpar o heap do aparelho para cada download, não me atenderia dimininuir o tamanhdo da imagem sendo que eu vou precisar dela do tamanho que ela é .

o problema se dá nessa ultima linha;

ByteArrayInputStream is = new ByteArrayInputStream(tempOut.toByteArray());
			
//                     BitmapFactory.Options options = new BitmapFactory.Options();
//                     options.inSampleSize = 1;
			
			Bitmap myBitmap = BitmapFactory.decodeStream(is);

alguem sabe como isso funciona?

14 Respostas

Xmio

Utilize um profiler para identificar o seu gargalo. Lembre sempre de limpar as instancias que você esta carregando as imagens para evitar que elas fiquem em memoria.
Fiz um post a alguns dias sobre como resolvi um memory leak bem cabreiro… você pode ver aqui: www.jemiliod.blogspot.com

E
ByteArrayInputStream is = new ByteArrayInputStream(tempOut.toByteArray());  
            Bitmap myBitmap = BitmapFactory.decodeStream(is);

Depois de você usar o ByteArrayInputStream, você o fecha (método close()) ?

O Garbage Collector não fecha tudo tão rapidamente quanto você quer. Se algo é aberto, deve ser fechado o mais rapidamente possível após o uso.

fabriciov

Em uma aplicação de camera ocorria o outOfMemory algumas vezes, diminui bem a ocorrencia utilizando o recycle, setando null para qualquer byte array utilizado e por fim chamando o gc.

Ja tentou gerar a bitmap direto do byteArray ?

danilorangelmg

Já tentei sim, ocorre a mesma coisa

Marky.Vasconcelos

Destruiu também as Views que voce as exibe? Setando images para null, recycle nos Bitmaps e setCallback(null) em Drawables?

danilorangelmg

Entao mark eu não as exibo eu faço o download e salvo no sd,

olha o codigo abaixo

System.out.println("Downloading: " + imageURL);
			HttpClient httpClient = new DefaultHttpClient();
			HttpGet httpGet = new HttpGet(URI.create(imageURL));

			//recebe a resposta
			HttpResponse httpResponse = httpClient.execute(httpGet);
			if(httpResponse.getStatusLine().getStatusCode() >= 400) {
				throw new Exception("Erro ao baixar imagem do servidor."+ httpResponse.getStatusLine().getStatusCode());
			}
			HttpEntity responseEntity = httpResponse.getEntity();
			InputStream input = responseEntity.getContent();
			byte[] buffer = new byte[1024];
			int sizeRead;
			ByteArrayOutputStream tempOut = new ByteArrayOutputStream();
			while ((sizeRead = input.read(buffer)) != -1) {
				tempOut.write(buffer, 0, sizeRead);
			}
			tempOut.flush();
			tempOut.close();
			ByteArrayInputStream is = new ByteArrayInputStream(tempOut.toByteArray());

			//            BitmapFactory.Options options = new BitmapFactory.Options();
			//            options.inSampleSize = 1;

			Bitmap myBitmap = BitmapFactory.decodeStream(is);
			//			Bitmap myBitmap = BitmapFactory.decodeStream(is, null, options);
			is.close();
			File nFile = null;
			if(myBitmap != null) {
				//verifica se o path padrao das imagens foi criado
				String path = App.IMAGE_PATH;
				File dir = new File(path+"/image");
				//se não existir cria o diretorio
				if (!dir.exists()) {
					dir.mkdir();
				}

				//a partir daqui a imagem é salva no diretorio
				nFile = new File(dir.getAbsolutePath(), fileName);
				createThumb(nFile, myBitmap);
				compressBitMap(myBitmap, nFile);

				myBitmap = null;
				System.gc();

============================================

		private void compressBitMap(Bitmap myBitmap, File nFile) throws FileNotFoundException, IOException {
			OutputStream fOut = new FileOutputStream(nFile);
			myBitmap.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
			fOut.flush();
			fOut.close();
			myBitmap.recycle();
		}

		private void createThumb(File file, Bitmap map) {
			try {
				// load the origial BitMap (500 x 500 px)
				int width = map.getWidth();
				int height = map.getHeight();

				int newWidth = 40;
				int newHeight = 40;
				if (App.SDK_VERSION >= 13) {
					newWidth = 100;
					newHeight = 100;
				}


				// calculate the scale - in this case = 0.4f
				float scaleWidth = ((float) newWidth) / width;
				float scaleHeight = ((float) newHeight) / height;

				// createa matrix for the manipulation
				Matrix matrix = new Matrix();
				// resize the bit map
				matrix.postScale(scaleWidth, scaleHeight);

				// recreate the new Bitmap
				Bitmap resizedBitmap = Bitmap.createBitmap(map, 0, 0, width, height, matrix, true);
				String pathThumb = file.getParent()+"/thumb";
				File tFile = new File(pathThumb);
				if (!tFile.exists()) {
					tFile.mkdir();
				}
				tFile = new File(tFile.getAbsolutePath()+"/"+file.getName());

				compressBitMap(resizedBitmap, tFile);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
Marky.Vasconcelos

Acredito que sejam as streams então.

danilorangelmg

como assim?

A

Olá
Já verificou se as 5000 imagens cabem no celular?
Já tentou retomar os dowloads a partir da última imagem baixada?

Marky.Vasconcelos

Por exemplo, sempre chame consumeContent() de HttpResponses e chame close() em Input/OutputStreams.

fabriciov

Se você vai apenas salvar não há necessidade de criar bitmaps (o que se deve evitar ao máximo por ser muito pesado).

Se você faz download de um servidor php:

URLConnection ucon = url.openConnection();
          InputStream inputStream = null;
          HttpURLConnection httpConn = (HttpURLConnection)ucon;
          httpConn.setRequestMethod("GET");
          httpConn.connect();

          if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
           inputStream = httpConn.getInputStream();
          }else{
          throws new NotResponseException();
          }
            FileOutputStream fos = new FileOutputStream(file);
            int size = 1024*1024;
            byte[] buf = new byte[size];
            int byteRead;
            while (((byteRead = inputStream.read(buf)) != -1)) {
                fos.write(buf, 0, byteRead);
                bytesDownloaded += byteRead;
            }
            fos.close();

Se é um link direto (ex: www.site.com/imagem.jpg

pode usar o downloadManager
http://developer.android.com/reference/android/app/DownloadManager.html

danilorangelmg

eu uso o bitmap pra comprimir em jpg

danilorangelmg

mais apesar que se eu garantir que a imagem seja jpg do lado do servidor eu nao preciso comprimir ela.

danilorangelmg

Galera aparentemente eu resolvi. retirei todos os bitmaps do metodos e salvei direto com o FileOutput e funcionou, resolvi garantir que a imagens vai chegar do jeito que eu preciso do lado do servidor.

Valeu a todos.

Criado 15 de julho de 2013
Ultima resposta 16 de jul. de 2013
Respostas 14
Participantes 6