Excel

Excel

Postby Sebastián Almirón » Fri May 09, 2008 6:28 pm

Hola a todos, perdonar por el tocho pero no se a quien recurrir.

Tengo una clase Excel propia que, aunque en general funciona bien, a veces me está dando problemas. Lo que he notado es que por algún motivo los objetos de la memoria no se liberan como debería.

A ver si me explico:

Primero situaros en el entorno: Tengo unos 5.000 libros de cálculo, cada uno contiene unas 30 hojas de las de 400 filas x 30 columnas, cada libro tiene aproximadamente 1 Mega, de los cuales extraigo unos 400 datos para formar referencias y unidades con el fin de formar las estructuras de productos de una fábrica (los materiales y manos de obra que llevan).
Mediante una plantilla que modifican los usuarios y utilizando un lenguaje basado en la clase TScript más un montón de funciones creadas para tal fin, de vez en cuando hay que recalcular las estructuras de todos los productos, proceso que suele tardar unas 30 horas.

El caso es que el proceso me suele dar problemas cuando lleva un buen rato, generalmente en forma de GPF o mediante un aviso del sistema indicándome que recursos insuficientes.

el método para crear el objeto excel es así:
METHOD New() CLASS TExcel
sysrefresh()
::OleExcel := CreateOleObject( "Excel.Application" )
sysrefresh()
return Self

Y para destruirlo así:
METHOD End() CLASS TExcel
if valtype(self) = 'O'
OleSetProperty(::OleExcel,'DisplayAlerts',.f.)
Oleinvoke(::OleExcel,'Quit')
Super:End()
OleUninitialize()
endif
return Nil

Para abrir el libro así:
METHOD OpenXls( cFileXls, lreadonly, lmessage ) CLASS TExcel
local sal
DEFAULT lreadonly := .f., lmessage := .t.
cfilexls := alltrim(cfilexls)

if lmessage = .t.
if !file( lfn2sfn(cFileXls) )
MsgAlert('No existe el libro de cálculo '+cfilexls)
return .f.
endif
else
if !file( lfn2sfn(cFileXls) )
return .f.
endif
endif
::OleXlss := OleGetProperty( ::OleExcel, 'Workbooks')
OleInvoke(::OleXlss, 'Open', cfilexls,,lreadonly)
::OleBook := OleGetProperty( ::OleExcel, 'ActiveWorkbook')
if valtype( ::OleBook ) = 'N'
::OleSheet := OleGetProperty( ::OleExcel, 'ActiveSheet')
::OleSelect := OleGetProperty( ::OleExcel, 'Selection')
::cFilexls := cFilexls
sal := .t.
else
sal := .f.
endif

::cFont := "Arial"
::nSize := 10
::lBold := .F.
::lItalic := .F.
::lUnderLine := .F.
::nAlign := 1

return sal

Y para cerrarlo así:
METHOD CloseBook() CLASS TExcel
local obook
if valtype(::OleBook) = 'N'
OleInvoke(::OleBook, 'Close', .f.)
::OleBook := OleGetProperty( ::OleExcel, 'ActiveWorkbook')
endif
sysrefresh()
return


Primero, si creo un objeto Excel y voy abriendo, tomando datos y cerrando los libros, la memoria usada por el objeto excel (en el administrador de tarea) va subiendo, cosa que creo no debería pasar si cierro el libro (he probado dejando excel visible), hasta que da un error de recursos insuficientes ( a veces un GPF por utilizar un objeto que no se ha podido crear por falta de memoria)

Pero es que además si ni siquiera abro libros, solamente:
oexcel := TExcel():New()
oexcel:End()

Aparentemente funciona, del administrador de tareas desaparece Excel, pero cada vez que creo un objeto Excel nuevo se añade un Objeto de Usuario que luego no se libera (Una de las columnas que podemos poner visible en los procesos del administrador de tareas) a ntvdm.exe, que creo que son la causa de mis problemas. De hecho la memoria usada por ntvdm.exe va subiendo a medida que abro libros y luego no llega a liberarse del todo ni siquiera si destruyo el objeto excel, que he probado a destruirlo y volverlo a crear cada 20 libros, con lo cual se soluciona el problema de memoria de excel, pero no de ntvdm.exe

Por supuesto esta clase me funciona bien en el resto de procesos, cuando lo normal es abrir una hoja o crearla para hacer un informe, etc. Incluso en el proceso descrito lo normal es que me dé el error cuando lleva el 50%, es decir después de haber procesado unos 2500 libros.


Bueno, resumiendo y para los que no quieran tragarse el royo anterior:

¿ Como hacer que un objeto Excel, creado con de OLE2 libere totalmente la memoria utilizada ¿ y como hacer que cuando se cierre un libro se libere también la memoria utilizada para ese libro ?

¿Podéis alguno probar con la clase Excel que utilicéis a ver si la memoria de ntvdm.exe se queda igual tras crear y destruir unas cuantas veces un objeto excel ?

Saludos
User avatar
Sebastián Almirón
 
Posts: 155
Joined: Mon Dec 12, 2005 9:56 am
Location: Moralzarzal - Spain

Postby Antonio Linares » Sat May 10, 2008 9:38 pm

Sebastián,

Tu aplicación esta en 16 bits ó en 32 bits ?

Te lo pregunto pues has puesto tu pregunta en el foro de Clipper. Pero por tu código diría que es 32 bits.

Y en caso de no ser de 32 bits, lo idóneo es que la pasaras a 32 bits, para evitar problemas de memoria.
regards, saludos

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

Postby Sebastián Almirón » Mon May 12, 2008 8:49 am

Hola Antonio

Esta es una aplicación de 16 bits.

Por ser muy compleja (llevo 10 años trabajando en ella) no la he pasado a 32 bits ya que aunque se lo he propuesto al cliente, me ha pedido que aproveche cuando me embarque en ello para pasar las bases de datos a Oracle. Y estoy, cuando tengo un poco de tiempo, mirando como solucionar algunos problemas con el AdoRDD (índices, migrar las bases de datos, modificar los dialogos que todos tienen controles Borland, etc.). Algunas aplicaciones más pequeñas ya las tengo en 32 bits, pero esta tiene más de 200 bases de datos, alrededor de 1500 cuadros de dialogo y más de 300.000 líneas de código... me dá pavor meterme a ello.

Saludos
User avatar
Sebastián Almirón
 
Posts: 155
Joined: Mon Dec 12, 2005 9:56 am
Location: Moralzarzal - Spain


Return to FiveWin para CA-Clipper

Who is online

Users browsing this forum: No registered users and 3 guests