[Delphi] At runtime geladen package laadt unit tweede keer

Pagina: 1
Acties:

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 08-05 18:37

Tomatoman

Fulltime prutser

Topicstarter
Aangezien ik bij het werken met packages wat onverklaarbaar gedrag tegenkwam, heb ik een kleine testapplicatie gebouwd. Dit zijn de twee scenario's:
• Een executable wordt gebuild met runtime packages. Terwijl het programma draait wordt met LoadPackage nog een extra package geladen. Alles werkt normaal.
• Dezelfde executable wordt gebuild, maar nu zonder runtime packages. Terwijl het programma draait wordt met LoadPackage hetzelfde extra package geladen. Globale variabelen in de applicatie vertonen vreemd gedrag.

Al testende kwam ik erachter wat het verschil is. Als je runtime packages gebruikt worden units zoals Forms via packages geladen (Forms zit in VCL70.bpl). Als je later een extra package laadt, gebruikt dat package de Forms unit in het reeds eerder geladen package VCL70.bpl.

Als je daarentegen geen runtime packages gebruikt, worden units zoals Forms meegecompileerd in de executable. Als je later een extra package laadt dat Forms nodig heeft, laadt het op dat moment VCL70.bpl. Op dat moment heb je dus twee instanties van de Forms unit in de applicatie, namelijk de eerste die in de executable is meegecompileerd en de tweede die later via een package is geladen.

Natuurlijk geeft die tweede situatie problemen. Neem bijvoorbeeld de globale variabele Screen in de Forms unit. Alle units in de executable gebruiken de Screen variabele in de executable, terwijl alle units in het later geladen package de Screen variabelen in VCL70.bpl gebruiken. Je hebt dus opeens twee Screen variabelen!

Lang verhaal, korte vraag: hoe kan ik vanuit een met LoadPackage geladen package alsnog toegang krijgen tot de globale variabelen die zijn meegecompileerd in de executable?

Als het verhaal onduidelijk is wil ik de testcode er wel bijzetten, maar voorlopig lijkt me deze post wel lang genoeg :)

Een goede grap mag vrienden kosten.


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Dat klopt. Je krijgt hetzelfde effect met 'gewone' DLL's. Naast Screen is Application vaak nog een veel belangrijkere globale variable die je ook dubbel krijgt. Wat vaak gedaan wordt is het doorgeven van deze variablen van de EXE naar de DLL, of in dit geval BPL, zodat ze beide gelijk zijn.

Bovendien zijn dit nog niet je enige problemen. Binnen je process bestaan nu ook twee kopieen van de VCL. Eentje gecompiled in je EXE en eentje in je DLL/BPL. Er bestaan dus twee implementaties van TEdit bijvoorbeeld. Zolang je beide met precies dezelfde versie van Delphi compiled en draait is er niets aan de hand, totdat je gaat kijken of een bepaald object van een bepaald type is. Delphi vergelijkt de VMT's van beide en ziet dat deze verschillen. Terwijl je aan de buitenkant zou denken dat het precies dezelfde classes zijn. zie onderstaande code
Delphi:
1
2
3
// Uitgevoerd in de EXE
if MijnEditUitBPL is TEdit then
  ShowMessage('Hier komen we nooit!');


Maar aangezien je runtime packages al gebruikt als plugin structuur zie ik niet waarom je je EXE ook niet van runtime packages gebruik laat maken. Je hebt ze toch al nodig en al de bovenstaande problemen verdwijnen en als extra bonus wordt je EXE ook nog kleiner.

We adore chaos because we like to restore order - M.C. Escher


Verwijderd

Packages gebruiken voor plugins (zoals bv. Mark Miller doet in CodeRush) zie ik wel zitten.
Maar wanneer je je core packages (vcl70.bpl, etc.) niet meecompileert in je exe, levert dat meer problemen en nadelen op dan voordelen.

En je exe kleiner maken kan ook prima met UPX. Gratis, open source, en het werkt fantastisch!
Een Delphi exe van ruim 11MB weet 'ie terug te brengen tot 3MB. Ter vergelijking: WinZip maakt van die exe een zipfile van 4.3MB... En er is geen sprake van merkbare vertraging bij het opstarten van de applicatie, zelfs niet op m'n laptopje (een P3 600MHz).

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Kan je ook aangeven waarom je vindt dat runtime packages meer problemen opleveren dan ze oplossen? Natuurlijk zijn er ook nadelen aan het gebruik van runtime packages, maar afhankelijk van het doel dat je hebt zijn ze erg goed bruikbaar.

De grote van mijn binaries boeit me niet zo heel erg in deze tijd van de goedkope MB's, maar als je toch al runtime packages moet meeleveren lijkt het me een simpele winst met alleen maar voordelen. Er zitten ook nadelen aan het gebruik van exe compressors als UPX:
Why not use an EXE compressor?
Some have asked why I made StripReloc when there are EXE compression programs such as ASPack and UPX that will trim more bytes off of executables than StripReloc ever could.

The reason is there are downsides to using EXE compressors. Most notably:
  • Upon startup of a compressed EXE/DLL, all of the code is decompressed from the disk image into memory in one pass, which can cause disk thrashing if the system is low on memory and is forced to access the swap file. In contrast, with uncompressed EXE/DLLs, the OS allocates memory for code pages on demand (i.e. when they are executed).
  • Multiple instances of a compressed EXE/DLL create multiple instances of the code in memory. If you have a compressed EXE that contains 1 MB of code (before compression) and the user starts 5 instances of it, approximately 4 MB of memory is wasted. Likewise, if you have a DLL that is 1 MB and it is used by 5 running applications, approximately 4 MB of memory is wasted. With uncompressed EXE/DLLs, code is only stored in memory once and is shared between instances.
bron: http://jrsoftware.org/striprlc.php

We adore chaos because we like to restore order - M.C. Escher


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 08-05 18:37

Tomatoman

Fulltime prutser

Topicstarter
Het probleem met VMT's waar LordLarry op wijst kende ik nog niet. Dat lijkt me reden te meer om als je dynamisch packages laadt de hele applicatie met packages te builden. De structuur waarbij een applicatie slechts gedeeltelijk met packages wordt gebouwd en de rest wordt meegecompileerd levert zo te zien nogal enge problemen op.

Is er een nette manier om uit te vinden of een variabele naar een objectinstantie in een runtime package verwijst of naar een objectinstantie in de main executable?

Een goede grap mag vrienden kosten.


Verwijderd

LordLarry schreef op zaterdag 09 april 2005 @ 12:27:
Kan je ook aangeven waarom je vindt dat runtime packages meer problemen opleveren dan ze oplossen?
Vooral deployment, onderhoud en support. Stel dat een klant om wat voor reden dan ook besluit om vcl70.bpl van D7 terugzet, en het programma heeft de update pack 1 versie nodig? Kan de supportafdeling een fiks aantal uren kosten om uit te zoeken waarom 't "opeens" niet meer werkt...

Of je hoofdapplicatie wordt gecompileerd met een nieuwere versie, maar die sharet z'n bpl's met een aantal randapplicaties die nog niet gehercompileerd zijn? Ik maak software voor hotels, en daar is het gebruikelijk dat er tussen de 5 en 20 interfaces draaien die communiceren met het sleutelkaartsysteem, de telefooncentrale, de minibar, diverse creditcard systemen, centrale reserveringssystemen (web, GDS), etc., etc.

Dat zou inhouden dat je ook meteen al je randapplicaties moet hercompileren, maar soms MAG dat niet eens: vooral creditcard maatschappijen zijn daar nogal streng in, en certificeren een specifieke versie van je interface. Bij hercompilatie met een andere versie van de compiler ben je die certificatie al weer kwijt.
De grote van mijn binaries boeit me niet zo heel erg in deze tijd van de goedkope MB's, maar als je toch al runtime packages moet meeleveren lijkt het me een simpele winst met alleen maar voordelen. Er zitten ook nadelen aan het gebruik van exe compressors als UPX:
Het eerste argument (disk trashing) is m.i. een broodje aap verhaal. De gecomprimeerde exe wordt eerst ingelezen, en dan pas uitgepakt. Dat daardoor in extreme situaties je swapfile vol kan raken klopt, maar dat zorgt niet voor harddisk corrupties, etc.

Het 2e argument klopt helemaal: je kunt dan geen dll's etc. meer sharen. Maar in 99% van de gevallen draait bij onze klanten de applicatie maar 1x (sterker nog, ze kunnen 'm niet nogmaals met dezelfde instellingen opstarten).
Bij de klanten die met bv. Terminal Server werken, leveren we gewoon de ongecomprimeerde versie. Die hebben dan ook niet het nadeel dat een exe van 11MB over het net getrokken moet worden. Bij alle installaties staat de exe op een centrale server, en dan is 't wel prettig dat 't maar 3MB is ipv 11.

"Elk voordeel hep se nadeel". :)

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

tomatoman schreef op zaterdag 09 april 2005 @ 12:53:
Is er een nette manier om uit te vinden of een variabele naar een objectinstantie in een runtime package verwijst of naar een objectinstantie in de main executable?
Nee, ik zou zo geen nette manier weten. De niet nette manier is proberen te achterhalen in welk deel van het process de VMT zit en dan kijken welke module daar geladen is. Als alternatief voor de verwarende werking van 'is' zou je de classnames van beide classes kunnen vergelijken.

En er is nog een probleem waar je mee te maken krijgt tussen DLLs/BPLs en een EXE, namelijk de memory manager. Als je geen runtime packages gebruikt en ook geen ShareMem hebben beide een andere memory manager en kunnen elkaars geheugen niet vrijgeven. Dit geeft problemen bij het doorgeven van bijvoorbeeld strings of classes met strings er in.

[ Voor 19% gewijzigd door LordLarry op 09-04-2005 13:04 ]

We adore chaos because we like to restore order - M.C. Escher


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Verwijderd schreef op zaterdag 09 april 2005 @ 13:00:
Vooral deployment, onderhoud en support. Stel dat een klant om wat voor reden dan ook besluit om vcl70.bpl van D7 terugzet, en het programma heeft de update pack 1 versie nodig? Kan de supportafdeling een fiks aantal uren kosten om uit te zoeken waarom 't "opeens" niet meer werkt...
Dat klopt. En dat is ook zeker een goede rede om runtime packages niet overal voor te gebruiken, maar zoals ik al zei hangt het echt sterk van de situatie af of het nadeel groter is dan het voordeel. Ik denk dat dat bij dit geval zo is. Het niet gebruiken van runtime packages geeft veel meer problemen dan het zo veroorzaken als ze wel gebruikt worden. In .Net heb je alleen maar runtime packages (assemblies). Gelukkig hebben ze daar het versiebeheer wat gemakkelijker gemaakt.
Het eerste argument (disk trashing) is m.i. een broodje aap verhaal. De gecomprimeerde exe wordt eerst ingelezen, en dan pas uitgepakt. Dat daardoor in extreme situaties je swapfile vol kan raken klopt, maar dat zorgt niet voor harddisk corrupties, etc.
Er staat geen trashing, maar thrasing wat betekend dat de hardeschijf flink wordt benaderd. Met andere woorden: Er wordt mogelijk onnodig veel geswapped.

We adore chaos because we like to restore order - M.C. Escher


Verwijderd

LordLarry schreef op zaterdag 09 april 2005 @ 13:10:
In .Net heb je alleen maar runtime packages (assemblies). Gelukkig hebben ze daar het versiebeheer wat gemakkelijker gemaakt.
Ook daar hebben we al leuke dingen meegemaakt. DLL-hell wordt nu blijkbaar assembly-hell...
Een klant in Frankrijk had al Crystal Reports 9 (franse versie) geinstalleerd, en voor onze web reporting tools gebruiken wij de US versie. Na deployment werkten opeens de rapporten van hun boekhoudprogramma niet meer...
Zelfde versie, verschillende assemblies, blijkbaar.

Opgelost door onze software (incl. assemblies) op een eigen server te installeren, zodat die assemblies elkaar niet in de weg zitten. :)

  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 08-05 18:37

Tomatoman

Fulltime prutser

Topicstarter
Third-party runtime packages installeer ik tegenwoordig in de directory waar de executable geïnstalleerd is. Na enorme versieconflicten met de packages van Developer Express weet ik dat dat een hoop ellende scheelt. Dat levert wel de voordelen van runtime packages, maar niet de nadelen.

Een goede grap mag vrienden kosten.


  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 08-05 19:24

alienfruit

the alien you never expected

Opgelost door onze software (incl. assemblies) op een eigen server te installeren, zodat die assemblies elkaar niet in de weg zitten. :)
hmm.. Volgens mij kan je toch per applicatie zeggen welke versie van de assemblies het moet gebruiken? Via een configuratie bestand, bij mijn weten kun je dan van versie wisselen qua assemblies. Dat deden ze bij Delphi 2005 ook, anders kreeg ook versie conflicten als je C#Builder er al op had staan.
Pagina: 1