jueves, 29 de enero de 2015

Harbour. The Lost of Memory. 1 PARTE

Desarrollando una nueva aplicación, que nos va a  servir de puente para accerder desde la web a nuestros datos, me encuentro que quiero hacer un test de estres a ver que tal se comporta.

La sorpresa es que el viendo el consumo de memoria este se dispara expotencialmente.

Para ello he preparado un test, para dar cual puede ser el motivo de porque Harbour no libera la memoria. Ver más abajo

El problema es del uso de la clase TXMLDocument.

Usando la librería minixml, el problema desaparece, o al menos no es tan acusado como la otra solución.

Para ello, he actualizado Harbour con git, lo he vuelto a construir;

Harbour 3.2.0dev (r1411121701)
Copyright (c) 1999-2014, http://harbour-project.org/

Harbour Build Info
---------------------------
Version: Harbour 3.2.0dev (r1411121701)
Compiler: Borland C++ 5.5.1 (32-bit)
Platform: Windows XP 5.1.2600 Service Pack 2
PCode version: 0.3
ChangeLog last entry: 2014-11-12 18:01 UTC+0100 Przemyslaw Czerpak (druzus/at/po
czta.onet.pl)
ChangeLog ID: 92755e4480f06f6ee0dcf31e5e8e378bcb855c1b
Built on: Nov 14 2014 16:36:00
Build options: (tracing) (Clipper 5.3b) (Clipper 5.x undoc)


Pongo las imágemes antes de hacer cualquier llamada, 2 MB de RAM;




Ahora vamos a ataca a hacerle cientos de llamadas, http://127.0.0.1/xml_doc , y he aquí la sorpresa, unos 81.7MB de RAM;




 Ahora, vamos a atacar a http://127.0.0.1/xml_mini, que es la solución usando la librería, minixml;
 aunque se dobla el consumo de memoria, esta no se "desmadra", consumiendo solamente 4.7Mb




¿ Alguién puede verificar o encontrar la manera donde esta el error en TXMLDocument ?


Code Source:
// ---. cut ---------. cut ---------. cut ---------. cut ---------. cut ---------. cut ---------. cut ---------. cut ------
#include "hbthread.ch"
#include "Hblog.ch"

STATIC s_hMutex
STATIC s_lLog4Harbour := .T.

MEMVAR get, post, server

FUNCTION HB_GTSYS()
   REQUEST HB_GT_WVT_DEFAULT
RETURN NIL

/*---------------------------------------------------------------------------------------------*/
/* Entrada al servidor WEB */
/*---------------------------------------------------------------------------------------------*/
#include "fileio.ch"

FUNCTION Main( cParam1, cParam2 )
   LOCAL lMutex
   LOCAL n := 0
   Local lCreateThread := hb_mtvm()

   if lCreateThread
      run_web()
   endif  
   
   hb_MemoWrit( ".uhttpd.stop", "" )  // ESTO PARA el servidor WEB


RETURN

 
#require "hbssl"
#require "hbhttpd"

/*---------------------------------------------------------------------------------------------*/
procedure run_web( )

   LOCAL oServer

   LOCAL oLogAccess
   LOCAL oLogError

   LOCAL nPort := 1092
  

   IF hb_argCheck( "stop" )
      hb_MemoWrit( ".uhttpd.stop", "" )
      RETURN
   ELSE
      FErase( ".uhttpd.stop" )
   ENDIF

   oLogAccess := UHttpdLog():New( hb_dirBase() +"web_access.log" )

   IF ! oLogAccess:Add( "" )
      oLogAccess:Close()
      RETURN
   ENDIF

   oLogError := UHttpdLog():New( hb_dirBase() +"web_error.log" )
  
   IF ! oLogError:Add( "" )
      oLogError:Close()
      oLogAccess:Close()
      RETURN
   ENDIF

   oServer := UHttpdNew()

   IF ! oServer:Run( { ;
         "FirewallFilter"      => "", ;
         "LogAccess"           => {| m | oLogAccess:Add( CStr( m  )+ hb_eol() ) }, ;
         "LogError"            => {| m | oLogError:Add( Cstr( m  )+ hb_eol() ) }, ;
         "Trace"               => {| ... | QOut( ... ) }, ;
         "Port"                => nPort, ;
         "Idle"                => {| o | iif( hb_FileExists( ".uhttpd.stop" ), ( FErase( ".uhttpd.stop" ), o:Stop() ), NIL ) }, ;
         "SSL"                 => .F.,;
         "Mount"          => { ;
             "/info"             => {|| informarcion() }, ;
             "/xml_mini"         => {|| play_xml() }, ;
             "/xml_doc"          => {|| play_doc() }, ;
             "/"                 => {|| UWrite( "Hello!" ) } } } )

      oLogError:Close()
      oLogAccess:Close()
      ErrorLevel( 1 )
      RETURN
   ENDIF

   oLogError:Close()
   oLogAccess:Close()

   RETURN

/*
 Devuelve información del Entorno
*/
static function informarcion()
       UWrite( '<h2>Version Test : '+ "df_Version" +'</h2>' )
return UProcInfo()



// --------------------------------------------------------------------------------//
// Usando MiniXML apenas se nota consumo de memoria.
// --------------------------------------------------------------------------------//
function play_xml()
  local xml, cStr := space( 100000 ), data, htree, x
 
  xml := mxmlNewXML("1.0")
  data = mxmlNewElement(xml, "SetConceptoHotelPMSRS")
         mxmlElementSetAttr( data, "CODIGOHOT", "" )

  for x := 1 to 10
      hTree = mxmlNewElement( data, "CONCEPTO" )
              mxmlElementSetAttr( htree, "PAX", alltrim( Cstr( x ) ) )
  next      
 
  mxmlSaveString( xml , @cStr )
  mxmlDelete( xml )

  UAddHeader( "Content-Type", "text/xml;charset=utf-8" )

return UWrite( cStr )




// --------------------------------------------------------------------------------//
// Usando TXMLDOC grave problema de memoria
// --------------------------------------------------------------------------------//

#include "hbclass.ch"
#include "hbxml.ch"

function play_doc(  )
   Local oTarifas
   Local cEncoding := "ISO-8859-1"

  
   oTarifas := Twebtarifas():New()
   for x := 1 to 10
       oTarifas:Append( X )
   next

   UAddHeader( "Content-Type", "text/xml;charset=utf-8" )
   UWrite( oTarifas:WriteXML() )

RETURN nil



// --------------------------------------------------------------------------------//
// --------------------------------------------------------------------------------//
CLASS TGeneric
      DATA CodigoHot  INIT ""
      DATA IDUSER INIT "0"
      DATA oDoc
      DATA lUTF8 INIT .F.

ENDCLASS


// --------------------------------------------------------------------------------//
// --------------------------------------------------------------------------------//
CLASS Twebtarifas from TGeneric
      DATA aTarifas
   
      DATA Operacion   INIT "SetConceptoHotelPMSRS"

      METHOD New() CONSTRUCTOR
      METHOD WriteXML()
      METHOD Append( cCodigo, cDescripcion  )
      METHOD CreateXML()

ENDCLASS

// --------------------------------------------------------------------------------//
METHOD New( ) CLASS Twebtarifas
   ::aTarifas := {}
RETURN Self

METHOD CreateXML( ) CLASS Twebtarifas
Local oNode, oNodeP, oRes

    cEncoding := "UTF-8"
   ::oDoc := TXmlDocument():New() // Creacion del documento respuesta....
   ::oDoc:oRoot:AddBelow( TxmlNode():New( HBXML_TYPE_PI,'xml' , , 'version="1.0" encoding="'+ cEncoding +'" ' ) )

RETURN ::oDoc:oRoot


// --------------------------------------------------------------------------------//
METHOD WriteXML() CLASS Twebtarifas
   Local oNode, oNodeP, oNodeConcepto, aTarifa

   oNode := ::CreateXML()

   oNodeP := TxmlNode():New( HBXML_TYPE_TAG, ::Operacion  )
             oNodeP:SetAttribute( "CODIGOHOT", ::CodigoHot )
             oNodeP:SetAttribute( "IDUSER",    ::IdUser )

   oNode:AddBelow( oNodeP )

   if !empty( ::aTarifas )
      for each aTarifa in ::aTarifas
          oNodeConcepto := TxmlNode():New( HBXML_TYPE_TAG, "CONCEPTO" )
             oNodeConcepto:SetAttribute( "PAX",      UHtmlEncode( aTarifa[1] ) )
          oNodeP:AddBelow( oNodeConcepto )
      next
   endif

RETURN ::oDoc:ToString()

METHOD Append( nPax ) CLASS Twebtarifas
  AADD( ::aTarifas, { alltrim( Cstr( nPax ) ) } )
RETURN NIL

No hay comentarios:

Publicar un comentario

Android y Git. Disponer del hash automáticamente.

Una de las cosas a las que estoy acostumbrado, es tener siempre en mi código, el hash/tag/versión del control de versiones que estoy usan...