oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby A.Martinez » Thu Dec 15, 2011 9:23 am

Hola a todos,

He observado que cuando pinto un bitmap (se observa mejor en los bitmaps grandes) con oPrinter:SayBitMap() de la clase TPrinter se me produce una fuga de memoria. Lo observo con un una utilidad de sistema que me va diciendo la memoria usada en %. Cuando el .bmp es pequeño, al ser un % pequeño no se observa, pero cuando se hace la operacion varias veces o el bitmap es grande entonces se ve que la memoria no es released hasta que se sale del programa.
Entiendo que este no debe ser el comportamiento de GlobalAlloc()/ GlobalFree()

La verdad es que me corre prisa solucionarlo. Agradecido de antemano siquiera por alguna pista.
Anexo metodo (original) TPrinter():SayBitMap (Fwh 7.12/ xHarbour 1.0).
Code: Select all  Expand view

//----------------------------------------------------------------------------//

METHOD SayBitmap( nRow, nCol, xBitmap, nWidth, nHeight, nRaster ) CLASS TPrinter

   local hDib, aBmpPal, hBitmap, hPalette

   if ::hDC = 0
      return nil
   endif

   if ( ValType( xBitmap ) == "N" ) .or. ! File( xBitmap )
      aBmpPal  = PalBmpLoad( xBitmap )
      hBitmap  = aBmpPal[ 1 ]
      hPalette = aBmpPal[ 2 ]
      hDib   = DibFromBitmap( hBitmap, hPalette )
      PalBmpFree( hBitmap, hPalette )
   else
      hDib = DibRead( xBitmap )
   endif

   if hDib == 0
      return nil
   endif

   if ! ::lMeta
      hPalette = DibPalette( hDib )
   endif

   DibDraw( ::hDCOut, hDib, hPalette, nRow, nCol,;
            nWidth, nHeight, nRaster )

   GlobalFree( hDib )

   if ! ::lMeta
      DeleteObject( hPalette )
   endif

return nil

 


Saludos
Last edited by A.Martinez on Thu Dec 15, 2011 11:56 am, edited 1 time in total.
A.Martinez
 
Posts: 8
Joined: Thu Dec 15, 2011 12:12 am

Re: oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby A.Martinez » Thu Dec 15, 2011 11:55 am

Hola,

Dejo como test del problema el TestPrn2.Prg que demuestra lo que digo: la pérdida/ fuga de memoria. La memoria se recupera solo al salir del programa. El problema se puede comprobar más facilmente imprimiendo pocos bitmaps, cuando el bitmap es grande, o bien, si es pequeño, imprimiendo muchas veces el bitmap.

Code: Select all  Expand view

//----------------------------------------------------------------------------//
// Samples\TestPrn2.Prg
 function TestPerdidaDeMemoria()

   local oPrn, oFont
   local nRowStep, nColStep
   local nRow := 0, nCol := 0, n, m
   Local nMio
   
   IF !File("..\bitmaps\fivewin.bmp")
       msginfo("Se necesita ..\bitmaps\fivewin.bmp para hacer el test !!")
       return nil
   ENDIF
   
   // PrnSetSize( 2100, 1200 )     To adjust a different printer paper size!

   PRINT oPrn NAME "Testing the printer object from FiveWin" PREVIEW

      if Empty( oPrn:hDC )
         return nil          // Printer was not installed or ready
      endif

      DEFINE FONT oFont NAME "Ms Sans Serif" SIZE 0, -12 OF oPrn

      nRowStep = oPrn:nVertRes() / 20   // We want 20 rows
      nColStep = oPrn:nHorzRes() / 15   // We want 15 cols
      for nMio:= 1 to 400
      PAGE
         oPrn:SayBitmap( 1, 1, "..\bitmaps\fivewin.bmp" )
         for n = 1 to 20  // rows
             nCol = 0
             oPrn:Say( nRow, nCol, Str( n, 2 ), oFont )
             nCol += nColStep
             for m = 1 to 15
                oPrn:Say( nRow, nCol, "+", oFont )
                nCol += nColStep
             next
             nRow += nRowStep
         next
         oPrn:Line( 0, 0, nRow, nCol )
      ENDPAGE
      next
      for nMio:= 1 to 400
      PAGE
         nRow = 0
         oPrn:SayBitmap( 1, 1, "..\bitmaps\fivewin.bmp" )
         for n = 1 to 20  // rows
             nCol = 0
             oPrn:Say( nRow, nCol, Str( n + 20, 2 ), oFont )
             nCol += nColStep
             for m = 1 to 15
                oPrn:Say( nRow, nCol, "+", oFont )
                nCol += nColStep
             next
             nRow += nRowStep
         next
         oPrn:Line( 0, 0, nRow, nCol )
      ENDPAGE
      next

   ENDPRINT

   oFont:End()      // Destroy the font object

return nil

 


Saludos
A.Martinez
 
Posts: 8
Joined: Thu Dec 15, 2011 12:12 am

Re: oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby Antonio Linares » Thu Dec 15, 2011 1:41 pm

A.

Prueba asi:

Code: Select all  Expand view
  ...    
      aBmpPal  = PalBmpLoad( xBitmap )
      hBitmap  = aBmpPal[ 1 ]
      hPalette = aBmpPal[ 2 ]
      hDib   = DibFromBitmap( hBitmap, hPalette )
      // PalBmpFree( hBitmap, hPalette )
      DeleteObject( hBitmap )
      DeleteObject( hPalette )
      ...
 
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby A.Martinez » Thu Dec 15, 2011 3:49 pm

Antonio,

Muchas gracias por responder. Lamentablemente no ha funcionado. Lo he probado con PalBmpRead() puesto que tengo el bitmap en disco. Aquí te dejo como ha quedado el metodo despues de las modificaciones:
Code: Select all  Expand view

METHOD SayBitmap( nRow, nCol, xBitmap, nWidth, nHeight, nRaster ) CLASS TPrinter

   local hDib, aBmpPal, hBitmap, hPalette

   if ::hDC = 0
      return nil
   endif

   if ( ValType( xBitmap ) == "N" ) .or. ! File( xBitmap )
      aBmpPal  = PalBmpLoad( xBitmap )
      hBitmap  = aBmpPal[ 1 ]
      hPalette = aBmpPal[ 2 ]
      hDib     = DibFromBitmap( hBitmap, hPalette )
      PalBmpFree( hBitmap, hPalette )
   else
      ******** Yo uso bitmaps desde fichero .bmp **********
//      hDib = DibRead( xBitmap )
      aBmpPal  = PalBmpRead(::hdc,  xBitmap )
      hBitmap  = aBmpPal[ 1 ]
      hPalette = aBmpPal[ 2 ]
      hDib     = DibFromBitmap( hBitmap, hPalette )
      DeleteObject(hBitMap)
      DeleteObject(hPalette)
   endif

   if hDib == 0
      return nil
   endif

   if ! ::lMeta
      hPalette = DibPalette( hDib )
   endif

   DibDraw( ::hDCOut, hDib, hPalette, nRow, nCol,;
             nWidth, nHeight, nRaster )

   GlobalFree( hDib )

   if ! ::lMeta
      DeleteObject( hPalette )
   endif

return nil
 


Yo no se manejar el API Win32, y por eso quiza diga una tonteria: ¿ puede ser que la memoria no se libere hasta que el dispositivo ::hdcout sea released y si el dispositivo no es released entonces por eso queda la memoria pillada ? A este tema le he dado mil vueltas, dentro de mis limitaciones, y no he conseguido hasta ahora sacarle punta.

Saludos
A.Martinez
 
Posts: 8
Joined: Thu Dec 15, 2011 12:12 am

Re: oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby Antonio Linares » Thu Dec 15, 2011 4:46 pm

A.

Podemos seguir haciendo otras pruebas. Comenta esta línea y prueba a ver si hay algún cambio:

// DibDraw( ::hDCOut, hDib, hPalette, nRow, nCol,;
// nWidth, nHeight, nRaster )

gracias
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby A.Martinez » Thu Dec 15, 2011 4:59 pm

Antonio,

Antonio Linares wrote:A.

Podemos seguir haciendo otras pruebas. Comenta esta línea y prueba a ver si hay algún cambio:

// DibDraw( ::hDCOut, hDib, hPalette, nRow, nCol,;
// nWidth, nHeight, nRaster )
gracias


Comentando la funcion DibDraw(): NO dibuja nada y NO hay escape de memoria

Me encantaria seguir haciendo otras pruebas hasta dar con la tecla. Gracias
A.Martinez
 
Posts: 8
Joined: Thu Dec 15, 2011 12:12 am

Re: oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby Antonio Linares » Thu Dec 15, 2011 5:31 pm

Como compruebas la pérdida de memoria ?

El código fuente de DibDraw() está en FWH\source\winapi\dib.c pero no reserva/libera memoria.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby A.Martinez » Thu Dec 15, 2011 5:52 pm

Antonio,

La memoria, además de con GlobalMemoryStatusEx(), lo compruebo con una utilidad externa. Ambos devuelven siempre el mismo %, con lo que imagino que esta bien. En todo caso, cuando la carga de memoria es muy alta..., no se el %, entonces empieza a no pintar los bitmaps, como si no tuviese memoria... con lo que me lleva a pensar que ese % de memoria da un dato "bueno".
Code: Select all  Expand view


#pragma BEGINDUMP
#include "windows.h"
#include "hbapi.h"
#include "hbcomp.h"


HB_FUNC ( GLOBALMEMORYSTATUSEX  )
{
   MEMORYSTATUSEX mst;
   long nMem = hb_parnl(1);

   mst.dwLength = sizeof( MEMORYSTATUSEX );
   GlobalMemoryStatusEx( &mst );

   switch( nMem )
   {
      case 0:  hb_retnd( mst.dwMemoryLoad            ) ; break; // <- Con este compruebo la memoria usada (en %)
      case 1:  hb_retnd( mst.ullTotalPhys            ) ; break;
      case 2:  hb_retnd( mst.ullAvailPhys            ) ; break;
      case 3:  hb_retnd( mst.ullTotalPageFile        ) ; break;
      case 4:  hb_retnd( mst.ullAvailPageFile        ) ; break;
      case 5:  hb_retnd( mst.ullTotalVirtual         ) ; break;
      case 6:  hb_retnd( mst.ullAvailVirtual         ) ; break;
      case 7:  hb_retnd( mst.ullAvailExtendedVirtual ) ; break;
      default: hb_retnd( 0 ) ;
   }
}
#pragma ENDDUMP

 


Por decir algo: ¿ no sera que en DibDraw() algo se bloquea o queda sin release y eso impida a GlobalFree() hacer su trabajo ?
A.Martinez
 
Posts: 8
Joined: Thu Dec 15, 2011 12:12 am

Re: oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby Antonio Linares » Thu Dec 15, 2011 6:27 pm

A. (Antonio, Adolfo, Alfonso... ?) :-)

Prueba a implementar la función DibDraw() en tu aplicación y asi puedes hacerle modificaciones.

Añade este código al final de tu PRG principal:

Code: Select all  Expand view

#pragma BEGINDUMP

#include <windows.h>
#include <hbapi.h>

static LPSTR DibBits( LPBITMAPINFOHEADER lpBmp )
{
    LPSTR lpBits;
    WORD  wColors = DibNumColors( lpBmp ); // wDIBColors( lpBmp );

    lpBits  = ( (LPSTR) lpBmp ) + ( DWORD ) lpBmp->biSize;

    if( lpBmp->biSize == sizeof( BITMAPCOREHEADER ) )
       lpBits += wColors * sizeof( RGBTRIPLE );
    else
       lpBits += wColors * sizeof( RGBQUAD );

    return lpBits;
}

static BOOL DibDraw( HDC hDC, HGLOBAL hDib, WORD wCol, WORD wRow,
              HPALETTE hPalette, WORD wWidth, WORD wHeight, DWORD dwRop )
{
    LPBITMAPINFOHEADER lpBmp;
    LPSTR              lpBits;
    HPALETTE           oldPal = (HPALETTE) 0;
    HBITMAP            hBmpOld;

    lpBmp = ( LPBITMAPINFOHEADER ) GlobalLock( hDib );

    dwRop = ( dwRop == ( DWORD ) -1 ? SRCCOPY: dwRop );

    if( lpBmp )
    {
       lpBits = DibBits(lpBmp);

       if( hPalette )
       {
          oldPal = SelectPalette( hDC, hPalette, FALSE);
          RealizePalette( hDC );
       }

        if( ( wWidth == 0 ) || ( wHeight == 0 ) )
           SetDIBitsToDevice( hDC, wCol, wRow, lpBmp->biWidth,
                              lpBmp->biHeight, 0, 0, 0,
                              lpBmp->biHeight, lpBits, ( BITMAPINFO * ) lpBmp, DIB_RGB_COLORS );
        else
           StretchDIBits( hDC, wCol, wRow, wWidth, wHeight,
                          0, 0, lpBmp->biWidth, lpBmp->biHeight,
                          lpBits, ( BITMAPINFO * ) lpBmp, DIB_RGB_COLORS, dwRop );

        if( oldPal )
        {
           SelectPalette( hDC, oldPal, TRUE );
           RealizePalette( hDC );
        }

        GlobalUnlock( hDib );

        return TRUE;
    }
    return FALSE;
}

HB_FUNC( DIBDRAW ) // ( hDC, hMemBitmap, hPalette, nRow, nCol, nWidth, nHeight, nRop )
{
    HDC       hDC  = ( HDC ) hb_parnl( 1 );
    HGLOBAL   hDib = ( HGLOBAL ) hb_parnl( 2 );
    HPALETTE  hPal = ( HPALETTE ) hb_parnl( 3 );

    if( hDC && hDib )
       hb_retl( DibDraw( hDC, hDib, ( WORD ) hb_parni( 5 ), ( WORD ) hb_parni( 4 ), hPal,
                         ( WORD ) hb_parni( 6 ), ( WORD ) hb_parni( 7 ),
                         ( DWORD ) ( ( void * ) hb_parni( 8 ) != NULL ? ( DWORD ) hb_parni( 8 ): ( DWORD ) -1 ) ) );
}

#pragma ENDDUMP
 


Prueba a añadirlo a tu PRG y compueba si se compila bien y si funciona, gracias
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby A.Martinez » Thu Dec 15, 2011 6:57 pm

A. de Antonio :D

He puesto el codigo que me has enviado y he probado y todo sigue igual (sigue consumiendo memoria).
Luego he probado a comentar la StretchDIBits( ) y entonces he observado que NO pinta nada pero NO consume memoria.

Code: Select all  Expand view

    //       StretchDIBits( hDC, wCol, wRow, wWidth, wHeight, 0, 0, lpBmp->biWidth, lpBmp->biHeight,
    //                      lpBits, ( BITMAPINFO * ) lpBmp, DIB_RGB_COLORS, dwRop );
 
A.Martinez
 
Posts: 8
Joined: Thu Dec 15, 2011 12:12 am

Re: oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby Antonio Linares » Thu Dec 15, 2011 7:29 pm

Antonio,

Bueno, lo importante es que ya sabemos de donde viene el problema: función StretchDIBits().

Ahora pensemos una estrategia...

Miremos por ejemplo el código que use Wine para la función StretchDIBits():
http://cvs.winehq.org/cvsweb/wine/dlls/gdi/Attic/dib.c?rev=1.22&content-type=text/x-cvsweb-markup
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby Antonio Linares » Thu Dec 15, 2011 7:37 pm

Buscando en google veo que otros programadores (en otros lenguajes) han tenido problemas tambien con esta función:

http://stackoverflow.com/questions/8036855/how-to-handle-gdi-resource-leak

Quizá eso nos de una pista de por donde buscar...
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby Antonio Linares » Thu Dec 15, 2011 7:41 pm

Antonio,

Si no haces el PREVIEW (quitando esa clausula), se produce la misma pérdida ?

gracias por tus pruebas,
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby A.Martinez » Thu Dec 15, 2011 7:54 pm

Antonio,

RESPUESTA 1:
Pues siento decirte que creo que NO es la StretchDIBits() porque si modifico lo que me has mandado y pongo:

Code: Select all  Expand view

...
//        if( ( wWidth == 0 ) || ( wHeight == 0 ) )
        if( 1 )
           SetDIBitsToDevice( hDC, wCol, wRow, lpBmp->biWidth,
                              lpBmp->biHeight, 0, 0, 0,
                              lpBmp->biHeight, lpBits, ( BITMAPINFO * ) lpBmp, DIB_RGB_COLORS );
        else
//           StretchDIBits( hDC, wCol, wRow, wWidth, wHeight,
//                          0, 0, lpBmp->biWidth, lpBmp->biHeight,
//                          lpBits, ( BITMAPINFO * ) lpBmp, DIB_RGB_COLORS, dwRop );
...
 


Entonces la imagen SI se pinta, sin redimensionar (utilizando SetDIBitsToDevice()), pero SI hay fuga de memoria.

¿ Sera por alguna funcion comun para SetDIBitsToDevice() y StretchDIBits() ?

RESPUESTA 2:
Linea ! digo bingo ! Sin preview NO hay fuga.
A.Martinez
 
Posts: 8
Joined: Thu Dec 15, 2011 12:12 am

Re: oPrinter:SayBitmap/ GlobalAlloc-GlobalFree ¿fuga de memoria?

Postby A.Martinez » Fri Dec 16, 2011 8:20 am

Antonio,

Encontrado el problema; resulta que yo utilizo una RPreview modificada por algun compañero del foro, siento no recordar el nombre; es una RPreview que lleva una TListView con las miniaturas de las paginas. Pues bien, he puesto la preview original de fwh y YA NO HAY CONSUMO DE MEMORIA !!

Muchisimas gracias Antonio por tu ayuda, ha sido de gran valor.

Feliz Navidad !

Saludos
A.Martinez
 
Posts: 8
Joined: Thu Dec 15, 2011 12:12 am

Next

Return to FiveWin para Harbour/xHarbour

Who is online

Users browsing this forum: Google [Bot] and 78 guests