Pergunta

No processo de rastreamento de problemas graves de memória em meu aplicativo, observei vários despejos de heap do meu aplicativo e, na maioria das vezes, tenho um bitmap ENORME que não conheço.

São necessários 9,4 MB, ou 9.830.400 bytes, ou na verdade uma imagem de 1280x1920 com 4 bytes por pixels.

Eu verifiquei no Eclipse MAT, é de fato um byte[9830400], que tem uma referência de entrada que é um android.graphics.Bitmap.

Eu gostaria de despejar isso em um arquivo e tentar vê-lo.Não consigo entender de onde isso vem.Minha maior imagem em todos os meus drawables é um png 640x960, que ocupa menos de 3 MB.

Tentei usar o Eclipse para "copiar valor para arquivo", mas acho que ele simplesmente imprime o buffer no arquivo, e não conheço nenhum software de imagem que possa ler um fluxo de bytes e exibi-lo como 4 bytes por pixel imagem.

Qualquer ideia?

Aqui está o que eu tentei:despeje a matriz de bytes em um arquivo, envie-a para /sdcard/img e carregue uma atividade como esta:

@Override
public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    try {
        final File inputFile = new File("/sdcard/img");
        final FileInputStream isr = new FileInputStream(inputFile);
        final Bitmap bmp = BitmapFactory.decodeStream(isr);
        ImageView iv = new ImageView(this);
        iv.setImageBitmap(bmp);
        setContentView(iv);
        Log.d("ImageTest", "Image was inflated");
    } catch (final FileNotFoundException e) {
        Log.d("ImageTest", "Image was not inflated");
    }
}

Eu não vi nada.

Você sabe como é codificada a imagem?Digamos que esteja armazenado em byte[] buffer. buffer[0] é vermelho, buffer[1] é verde, etc?

Foi útil?

Solução 2

OK - Depois de algumas tentativas malsucedidas, finalmente consegui algo dessa matriz de bytes.Eu escrevi este programa C simples para converter a matriz de bytes em um arquivo Bitmap do Windows.Estou descartando o código caso alguém esteja interessado.
Compilei isso no VisualC 6.0 e gcc 3.4.4, deve funcionar em qualquer sistema operacional (testado em Windows, Linux e MacOS X).

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>

/* Types */
typedef unsigned char byte;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef int int32_t;

/* Constants */
#define RMASK 0x00ff0000
#define GMASK 0x0000ff00
#define BMASK 0x000000ff
#define AMASK 0xff000000

/* Structures */
struct bmpfile_magic {
  unsigned char magic[2];
};

struct bmpfile_header {
  uint32_t filesz;
  uint16_t creator1;
  uint16_t creator2;
  uint32_t bmp_offset;
};

struct bmpfile_dibheader {
  uint32_t header_sz;
  uint32_t width;
  uint32_t height;
  uint16_t nplanes;
  uint16_t bitspp;
  uint32_t compress_type;
  uint32_t bmp_bytesz;
  int32_t hres;
  int32_t vres;
  uint32_t ncolors;
  uint32_t nimpcolors;

  uint32_t rmask, gmask, bmask, amask;
  uint32_t colorspace_type;
  byte colorspace[0x24];
  uint32_t rgamma, ggamma, bgamma;
};

/* Displays usage info and exits */
void usage(char *cmd) {
    printf("Usage:\t%s <img_src> <img_dest.bmp> <width> <height>\n"
        "\timg_src:\timage byte buffer obtained from Eclipse MAT, using 'copy > save value to file' while selecting the byte[] buffer corresponding to an android.graphics.Bitmap\n"
        "\timg_dest:\tpath to target *.bmp file\n"
        "\twidth:\t\tpicture width, obtained in Eclipse MAT, selecting the android.graphics.Bitmap object and seeing the object member values\n"
        "\theight:\t\tpicture height\n\n", cmd);
    exit(1);
}

/* C entry point */
int main(int argc, char **argv) {
    FILE *in, *out;
    char *file_in, *file_out;
    int w, h, W, H;
    byte r, g, b, a, *image;
    struct bmpfile_magic magic;
    struct bmpfile_header header;
    struct bmpfile_dibheader dibheader;

    /* Parse command line */
    if (argc < 5) {
        usage(argv[0]);
    }
    file_in = argv[1];
    file_out = argv[2];
    W = atoi(argv[3]);
    H = atoi(argv[4]);
    in = fopen(file_in, "rb");
    out = fopen(file_out, "wb");

    /* Check parameters */
    if (in == NULL || out == NULL || W == 0 || H == 0) {
        usage(argv[0]);
    }

    /* Init BMP headers */
    magic.magic[0] = 'B';
    magic.magic[1] = 'M';

    header.filesz = W * H * 4 + sizeof(magic) + sizeof(header) + sizeof(dibheader);
    header.creator1 = 0;
    header.creator2 = 0;
    header.bmp_offset = sizeof(magic) + sizeof(header) + sizeof(dibheader);

    dibheader.header_sz = sizeof(dibheader);
    dibheader.width = W;
    dibheader.height = H;
    dibheader.nplanes = 1;
    dibheader.bitspp = 32;
    dibheader.compress_type = 3;
    dibheader.bmp_bytesz = W * H * 4;
    dibheader.hres = 2835;
    dibheader.vres = 2835;
    dibheader.ncolors = 0;
    dibheader.nimpcolors = 0;
    dibheader.rmask = RMASK;
    dibheader.gmask = BMASK;
    dibheader.bmask = GMASK;
    dibheader.amask = AMASK;
    dibheader.colorspace_type = 0x57696e20;
    memset(&dibheader.colorspace, 0, sizeof(dibheader.colorspace));
    dibheader.rgamma = dibheader.bgamma = dibheader.ggamma = 0;

    /* Read picture data */
    image = (byte*) malloc(4*W*H);
    if (image == NULL) {
        printf("Could not allocate a %d-byte buffer.\n", 4*W*H);
        exit(1);
    }
    fread(image, 4*W*H, sizeof(byte), in);
    fclose(in);

    /* Write header */
    fwrite(&magic, sizeof(magic), 1, out);
    fwrite(&header, sizeof(header), 1, out);
    fwrite(&dibheader, sizeof(dibheader), 1, out);

    /* Convert the byte array to BMP format */
    for (h = H-1; h >= 0; h--) {
        for (w = 0; w < W; w++) {
            r = *(image + w*4 + 4 * W * h);
            b = *(image + w*4 + 4 * W * h + 1);
            g = *(image + w*4 + 4 * W * h + 2);
            a = *(image + w*4 + 4 * W * h + 3);

            fwrite(&b, 1, 1, out);
            fwrite(&g, 1, 1, out);
            fwrite(&r, 1, 1, out);
            fwrite(&a, 1, 1, out);
        }
    }

    free(image);
    fclose(out);
}

Então, usando esta ferramenta consegui reconhecer a imagem usada para gerar esse bitmap de 1280x1920.

Outras dicas

Veja aqui uma resposta mais fácil: MAT (Eclipse Memory Analyzer) - como visualizar bitmaps de despejo de memória

DR - Instale o GIMP e carregue a imagem como RGB Alpha bruto

Descobri que a partir da versão mais recente do Android Studio (2.2.2 no momento da escrita), você pode visualizar o arquivo bitmap diretamente:

  1. Abra a guia ‘Monitor Android’ (no canto inferior esquerdo) e depois a guia Memória.
  2. Pressione o botão ‘Despejar Java Heap’

  3. Escolha o nome da classe ‘Bitmap’ para o instantâneo atual, selecione cada instância do bitmap e veja qual imagem exatamente consome mais memória do que o esperado.(telas 4 e 5)

  4. Escolha o Bitmap nome da classe…

enter image description here

  1. Selecione cada instância do bitmap

enter image description here

e clique com o botão direito nele, selecione View Bitmap

enter image description here

Basta levar a entrada para a imagem e convertê-la em um objeto bitmap usando o fileinput stream/datastream.Adicione também logs para ver os dados de cada imagem usada.

Você pode ativar uma conexão USB e copiar o arquivo para outro computador com mais ferramentas para investigar.

Alguns dispositivos podem ser configurados para transferir a tela atual para o sistema de arquivos quando o botão Iniciar é pressionado.Talvez isso aconteça com você.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top