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
Suscribirse a:
Enviar comentarios (Atom)
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...
-
Voy a publicar una serie de post sobre las funciones de threads que espero os sirva para comprender como podeis sacar provecho a ...
-
Después de más de 2 años, sacrificando fin de semanas y tiempo libre, he podido pasar a una versión totalmente funcional. El Sofware es ca...
-
Os muestro un pequeño video de las posibilidades de Harbour funcioanando como un servidor Web. Dentro de /contrib/httpd, tenéis un serv...
No hay comentarios:
Publicar un comentario