2012-03-08 6 views
6

Durante il processo di rilevamento di gravi problemi di memoria nella mia app, ho esaminato diversi dump dell'heap della mia app e il più delle volte ho una bitmap ENORME che non lo so.Come visualizzare effettivamente una bitmap prelevata da un dump dell'heap di Android

Richiede 9,4 MB, o 9,830,400 byte, o in realtà un'immagine 1280x1920 a 4 byte per pixel.

Ho verificato Eclipse MAT, è effettivamente un byte [9830400], che ha un riferimento in entrata che è un android.graphics.Bitmap.

Mi piacerebbe scaricare questo file in un file e provare a vederlo. Non riesco a capire da dove viene. La mia più grande immagine in tutti i miei drawable è un png 640x960, che richiede meno di 3 MB.

Ho provato a utilizzare Eclipse per "copiare valore su file", ma penso che stampi semplicemente il buffer sul file e non conosco alcun software di immagine in grado di leggere un flusso di byte e visualizzarlo come 4 byte per immagine pixel.

Qualche idea?

Ecco cosa ho provato: il dump l'array di byte in un file, premere a/sdcard/img, e caricare un'attività come questa:

@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"); 
    } 
} 

non ho visto niente.

Sai come è codificato l'immagine? Diciamo che è memorizzato in byte[] buffer. buffer[0] è rosso, buffer[1] è verde, ecc.?

+0

non è che solo la cache di rendering nativo? Esegui con l'accelerazione hardware abilitata? – Peterdk

+0

Sì, ho l'accelerazione HW. Ma questo non spiega perché il mio bitmap è stato upscaled del 200% e perché questa enorme bitmap è allocata nell'heap, IMHO. –

+0

Hai avuto fortuna a scoprire quale immagine fosse? Anch'io ho una tale immagine canaglia che occupa 1.1 MB e sembra provenire dalle risorse precaricate di Android. Quando guardo l'anteprima del buffer di byte usando GIMP, vedo un'immagine blu con gradiente radiale di dimensioni 1044x270. – c05mic

risposta

2

OK: dopo alcuni tentativi non riusciti, ho finalmente ottenuto qualcosa da questo array di byte. Ho scritto questo semplice programma C per convertire l'array di byte in un file Bitmap di Windows. Sto lasciando cadere il codice nel caso qualcuno sia interessato.
L'ho compilato con VisualC 6.0 e gcc 3.4.4, dovrebbe funzionare su qualsiasi sistema operativo (testato su 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); 
} 

Quindi, utilizzando questo strumento sono stato in grado di riconoscere l'immagine utilizzata per generare questo 1280x1920 bitmap.

+0

Mi chiedevo se avessi salvato il contenuto dell'array di byte in modo speciale su Mac OSX? Sono stato in grado di compilare il tuo codice ed eseguirlo sul contenuto del file che ho salvato da MAT ma il BMP risultante non può essere letto dal Visualizzatore immagini anteprima del Mac (supponendo che qualcosa non sia corretto con il file di origine dato il codice non esegue l'errore –

+0

Non ricordo esattamente, ho appena usato il "valore di copia in file" di Eclipse da MAT e ho eseguito il mio programma C su questo file. –

0

Basta prendere l'input per l'immagine e convertirlo in un oggetto bitmap utilizzando il file input stream/datastream. Aggiungete anche i log per vedere i dati per ogni immagine che viene utilizzata.

+0

Ho provato ma non visualizza nulla ... Vedi la mia modifica. –

0

È possibile abilitare una connessione USB e copiare il file su un altro computer con altri strumenti da esaminare.

Alcuni dispositivi potrebbero essere configurati per scaricare la schermata corrente sul file system quando viene premuto il pulsante di avvio. Forse questo succede a te.

+0

Grazie mille, ma non vedo come questo sia rilevante per il mio problema, e come avrebbe potuto aiutarmi a convertire l'array di byte preso da un dump dell'heap in un formato di immagine visualizzabile. –

0

ho scoperto che a partire dalla versione più recente di Android Studio (2.2.2 a partire dal scrittura), è possibile visualizzare il file bitmap direttamente:

  1. Aprire la scheda 'Android Monitor' (in basso a sinistra) e poi scheda di memoria.
  2. Premere il pulsante ‘Java Heap Dump’

  3. Scegliere il ‘Bitmap’ Nome Classe per l'istantanea corrente, selezionare ogni grado delle bitmap e visualizzare quale immagine esattamente consumano più memoria del previsto. (schermi 4 e 5)

  4. scegliere il nome Bitmap classe ...

enter image description here

  1. selezionare ogni grado delle bitmap

enter image description here

e fare clic destro su di esso , Selezionare View Bitmap

enter image description here

Problemi correlati