Avatar billede mbsnet Nybegynder
25. august 2007 - 14:54 Der er 24 kommentarer og
1 løsning

array of string = out of memory

Hej.

Når jeg putter meget data i et dynamisk "array of string" siger den "out of memory" selvom programmet kun tager 6-7 mb i windows task manager

Problemet opstår først når man kommer over et vis antal strings.
Er der nogle som kender årsagen ?

//mvh mbs
Avatar billede mbsnet Nybegynder
25. august 2007 - 14:57 #1
..burde den ikke bare blive ved til al ram er brugt..
Avatar billede hrc Mester
25. august 2007 - 15:42 #2
Array of const / string / integers er ikke til store mængder data. De er beregnet til at føre et valgfrit antal parametre over i en procedure, eksempelvis format('',[]). At du bruger konstruktionen til store dataklumper fortæller om en forkert løsning. Der findes lister såsom TList, TObject, TCollectionList (TCollectionItem) som er meget lette at bruge - og hurtigere.

Den bedste løsning er dog nok at benytte TClientDataSet, der er en tabel i hukommelsen. Det er nok den letteste løsning da den kræver meget lidt programmering - men en smule læsning før man forstår hvordan det hænger sammen. Kan i øvrigt indlæse/gemme data i XML-format.
Avatar billede hrc Mester
25. august 2007 - 15:43 #3
.. og nej jeg kender ikke årsagen til det du støder på ram-loftet. Mon ikke det er fordi det er et "hack" af en løsning?
Avatar billede mbsnet Nybegynder
25. august 2007 - 16:38 #4
Hej igen. Du hjalp også i høj grad sidst, hvor du forklarede det med at bruge klasser.

Nu har jeg rodet med at få bygget en "variabel container" og et "variabel arkiv", som i første omgang var bygget på tStringList, men så ændret til arrays for at prøve at opnå mere hastighed især. Nu siger du så at det ikke er den rigtige løsning. Bør jeg så lave det tilbage til stringList eller bruge TClientDataSet istedet.

Jeg sender lige den ene klasse for at vise formålet

type varContainer=class
procedure setVar(const varName:shortString;const theData:string);
function getVar(const varName:shortString):string;
function varString(containerName:shortString):string;
function varList(const indicator:char;const splitter:shortString):string;
function getName(const id:integer):shortString;
function listNames(const splitter:shortString):string;
procedure importVarList(const theList:string;const splitter:shortString);
function importVarFile(const dataType:char;const fileName:string):boolean;
function exportVarFile(const fileName:string):boolean;
procedure setVarByCmd(const cmd:string);
function importFromArchive(const archiveName:string):boolean;
procedure exportToArchive(theArchive:varArchive;const dataName:shortString);
procedure clearFocus;
procedure clear;
function focusVar(const varName:shortString):boolean;
function focusWhere(const paramName,matchValue:shortString):boolean;
function lookAt(const paramName:shortString):string;
function focusAndLookAt(const varName,paramName:shortString):string;
private
lastParamQuest:shortString;
public
varNames:tShortStringArray;  //navne
varData:tStringArray;        //data
changed:boolean;
curFileName:string;
curDataType:char;
varFocusNames:tShortStringArray;
varFocusData:tStringArray;
varCount,varFocusCount:integer;
focusedVar:shortString;
end;

De her funktioner kan så arbejde med tre forskellige datatyper
TYPE A: SINGLE PARAMETER:VALUE    (PER LINE) (adskilt med linieskift)
TYPE B: MULTIPLE $VAR=PARAM      (PER LINE) (adskilt med ;) (2 niveauer)
TYPE C: SINGLE VALUE              (PER LINE) (adskilt med linieskift)


Håber det giver mening. (de her strings kan i hvert fald blive lange hehe)
Avatar billede mbsnet Nybegynder
25. august 2007 - 18:32 #5
ok, det kunne godt se ud til at TClientDataset er en god løsning.
Det vil dog tage lidt tid at afprøve det ordentligt, men jeg vil
gerne give pointene, for det ser ud til at være godt ramt.
(send lige et svar)
Avatar billede mbsnet Nybegynder
26. august 2007 - 06:12 #6
Jeg har lige prøvet at lave et forsøg med en tStringList. Når jeg putter meget data ind i den møder jeg det samme problem, dog noget "senere".

Jeg har 2 gb ram, men kan kun få lov at bruge mellem 400mb- (hvis der er mange korte strings)- og 900mb (hvis der er få lange strings).

Kan man skrive et eller andet for at reservere mere ram eller hvad er det som sker her.
?

mvh Morten
Avatar billede martinlind Nybegynder
26. august 2007 - 15:37 #7
2 gb - windows xp ( ca. 500-600 mb ) - div - din exe fil = ca 900mb, det er nok ikke helt ved siden af at det er brugt op, mange små strings giver ligesom på din disk ( mange små filer ) en fragmenteret ram :) ( med mere eller mindre spild )

Der findes nogle "hack" som får windows til at smide det væk den ikke bruger, men klø på med TClientDataset, det er helt klart vejen frem, også til alle mulige andre prg.
Avatar billede mbsnet Nybegynder
26. august 2007 - 21:48 #8
Ok, havde ikke lige tænkt på ram også kunne være fragmenterede.
Det er heller ikke fordi jeg skal bruge så meget hukommelse i dette projekt. maks 200mb måske. Under alle omstændigheder er de 400-900mb bedre end de 6mb i array.

Nu har jeg skrevet det her projekt om til at bruge stringlist som før, og det virker helt klart bedre med større mængder data. Glæder mig til at få kendskab til TClientDataset, men lige nu var det jeg havde mest brug for at vide, at det var en forkert løsning med array of string. (og at stringlist'en gør det bedre)
Avatar billede hrc Mester
27. august 2007 - 10:14 #9
Hvis du skal forbi grænserne af en TStringList må du over i TObjectList. Hvert objekt du putter i den, er en selvstændig klump som ikke behøver ligge i samme klump hukommelse.

Eller naturligvis bruge TClientDataSet. Det kan være lidt forvirrende at den kan to ting: Enten fungere som en ram-baseret tabel i dit program, eller som en buffer til en database. Den kan begge og fungerer næsten som en TTable.

MartinLind: Fylder din Windows XP 900Mb? Det er ikke en Vista?. Min XP bruger 256Mb.
Avatar billede hrc Mester
27. august 2007 - 10:15 #10
Rettelse: ... klump som ikke behøver ligge i samme klump hukommelse som de andre objekter.
Avatar billede mbsnet Nybegynder
27. august 2007 - 10:40 #11
Hvad nu hvis man gerne vil benytte sig af en slags "shortstring"list,
eller en lang liste af sin egen type, måske "string[5]" som list. Det var her jeg troede man skulle bruge "array of string[5]" eller "array of stortstring".
Er det så stadigvæk clientDataSet, hvis det kun er een liste ?
Avatar billede martinlind Nybegynder
27. august 2007 - 12:01 #12
En XP-pro på et netværk med div drv. og virus-chk osv. skal helt ha min. 1gb for at køre nogenlunde og hvis du koder delphi skal du brug min. 1gb mere for at køre ordenligt, da delphi ide'en bruger en del :)

Nej du skal bruge en TList til en sådan liste, en TList er et array of pointere, så den kan indeholde alt hvad du har hukommelse til, det med de 6mb du løb ind i kunne også godt være fordi din var blev alloceret på stacken og ikke heapen.

Men du skal kigge på TList, TStringList, og de andre "TList" classer delphi har, de er ret gode til mange std. ting jeg har selv brugt dem til alt lige siden D1 ( 12 år )
Et TClientDataset er mest beregnet til noget hvor du har en Database :)
Avatar billede mbsnet Nybegynder
27. august 2007 - 12:29 #13
Nej 2 gb ram er jo i virkeligheden ikke for meget, nu om stunder :)
Jeg vil helt sikkert se nærmere på listerne. Kan godt lide sammenhængen mellem dem jeg kender i forvejen, stringlist, (memo og listbox) osv.

Det med pointere er nyt. Jeg har læst lidt om det de seneste dage i forbindelse med de array. Jeg var ikke klar over at det betød så meget omkring "hvordan" man smider ting og sager i hukommelsen. Så længe man bare kan bruge listerne, er det da okay.

Og forskellen på stack og heap er jeg også ubekendt med. Har vidst mødt et par "Stack overflow" en gang imellem :)
Avatar billede mbsnet Nybegynder
27. august 2007 - 12:30 #14
(i skal nok få points begge to for god baggrundsviden)
hrc, du må gerne lige sende et svar også
Avatar billede martinlind Nybegynder
27. august 2007 - 15:00 #15
ps. Delphi IDE og VCL bruger TList / TStringList ( TStrings ) rigtig meget de er hurtige og velgennemprøvede ( af samme grund )
Avatar billede hrc Mester
29. august 2007 - 09:43 #16
Hvis du bruger short strings så allokerer du altid den længde du definerer, en string[30] fylder 31 karakterer uanset om der står noget i den eller ej. Den skal du ikke bruge.

Du bør foretrække TObjectList fremfor TList da sidstnævnte:
  1. Bruger pointere. Det giver usikker kode
  2. Den frigiver ikke objekterne automatisk hvis man rydder listen

Hvis du laver en dataklasse og propper den i en TObjectList så bliver de alle frigivet igen når du Free'er listen - helt automatisk. Desuden er den mere sikker da den indeholder objekter i stedet for pointere (at det helt grundlæggende er en og samme ting - er en anden sag).
Avatar billede mbsnet Nybegynder
29. august 2007 - 18:50 #17
Hej. Jeg har været optaget af noget andet bøvl de sidste par dage. pyt :)

martinlind> Hvad betyder det med at Delphi VCL bruger TList

Btw: Fandt en ok beskrivelse omkring stack og heap, men kan ikke rigtig se hvordan man bruger den ene eller anden "sektion" i delphi.
http://www-ee.eng.hawaii.edu/~tep/EE160/Book/chap14/subsection2.1.1.8.html

hrc> Er det galt opfattet at shortString er bedre at bruge end string[255]

Jeg kunne se via google, at man kan putte tStringList'erne ind i TObjectList'en.

I det variabel-arkiv projekt jeg har gang i, er der P.T. 3 stringList, med masser af "spildplads" (Nu er der ikke nogle char/shortStrings eller noget):

archiveTypes,//Bruger en hel stringList, men der er kun 1 bogstav pr linje/string :)
archiveNames,//Det her er maks 50 pr linje, men bruger igen en hel stringlist
archive      //Det her er hele "tekstfiler" på "1 linje", adskilt med paragraf "§"
:tStringList;//---- altså rigtig lange strings.

Kan i give et eksempel på hvordan dette laves bedre med TList/TObjectList, således at det virker med noget ala char/string[1], shortString, string ?

Jeg vil gerne forstå det her med shortString ordentligt.
Hvis nu man har en string som altid er mellem 0 og 5 bogst.
Skal man så bruge string[5] eller shortString (op til 255)
Avatar billede mbsnet Nybegynder
29. august 2007 - 18:56 #18
(mere rigtigt: linjeskift er udskiftet med paragraf..)
Avatar billede hrc Mester
29. august 2007 - 21:50 #19
Mig bekendt er shortstring netop at du angiver længden (st: string[100])... men jeg kan tage fejl - tror dog ikke det er tilfældet her. Bruger du string (st: string) uden at angive længde, tager du fat i en skjult strengklasse der allokerer den mængde ram der er behov; helt op til 2GB. Medmindre al data du behandler har samme længde, er der ingen grund til at bruge shortstrings.

Glem i øvrigt TListen; den er til pointere og den slags bruges ikke længere. TObjectList er smartere, især hvis du laver en data-baseklasse og nedarver den til hhv. archivetype, archivename og archive. Så kan du have specialiserede klasser til dine data og en liste der kan indeholde alle typerne. Skal se om jeg kan brygge lidt sammen til dig.

Borlands VCL navnet på Borlands indpakning af det win32 API (Application Program(ming?) interface) som Microsoft stiller til rådighed - og som udgør vores adgang til Windows. De har lavet store (monstrøse) dll-biblioteker der indeholder knapper, listbokse og alt sådan noget, men det kaldes med pointere og helst med C eller C++ (og hvem gider det i dag?). det er ikke objektorienteret. Det pakkede Borland, med Anders Hejlsberg i spidsen, ind i noget Object Pascal og byggede derefter et velfungerende udviklingsmiljø ovenpå. Viola Delphi var født.
Avatar billede mbsnet Nybegynder
29. august 2007 - 22:52 #20
Shortstring passer med en byte.. (255) Begyndte egentlig med at bruge shortstring fordi jeg var i tvivl om hvis man sagde string[10] eller string[1],- om så den kunne have en længde på 0 (eller under det man satte den til). Men det kunne den jo så ifølge en lille test:) Når der ikke er ulemper ved bare at bruge string, kan det være man bare skal gøre det i stedet.

Det kunne være rart at komme i gang med at bruge de rigtige værktøjer, i stedet for at lave en masse forkert kode :) Vil meget gerne se mere omkring TObjectList

For ca en måned siden kom jeg ind på en side (mener det var delphi.about.com), hvor jeg første gang kunne se lidt om, hvad windows api er, og jeg kan godt se hvad du mener. Det ser ud til at størstedelen af de fleste programmer i virkeligheden er en del af windows. Synes dog det er lidt svært at komme ind på det helt konkret, med alle de $tal værdier for de forskellige muligheder osv.

Hvis man godt kan lide Microsoft og Bill Gates, så kan jeg anbefale et par gode lange videoer, hvor der holdes foredrag om eksempelvis Office Development. Første gang var jeg lige nødt til at holde en pause efter 20 minutter :)
http://www.microsoft.com/events/executives/billgates.mspx
Avatar billede hrc Mester
31. august 2007 - 23:42 #21
Er ved at lave et lille eksempel til dig. Er typerne forstået korrekt?

TYPE A: navn:værdi#13#10
TYPE B: navn:værdi1;værdi2#13#10
TYPE C: værdi#13#10

Hvad skal du med data når de er i listen? Skal de gennemløbes og analyseres bagefter?
Hvor stor mængde data skal der behandles? Hvor mange linjer?
Avatar billede mbsnet Nybegynder
01. september 2007 - 01:40 #22
Jep, type A bruger jeg som indtillinger. Hvis der er brug for flere grupper af indstillinger, kan jeg nu oprette en varibel med klassen til hver gruppe. Fks cfgCommon,cfgLocal,cfgFont:varContainer;
Derefter .create i initialization og .free i finalization :-)

Jeg bruger det i mange sammenhænge, primært som indstillinger / lister over data. Fks landekoder med forskelligt antal info pr land. Eller blot en filliste med navn på hver fil..
Alt det her forudsætter jo så, at man replace'er §$; med noget andet på forhånd.

{Type A} // fks. indstillinger for font (eller noget andet)
font.name:Tahoma
font.size:10
font.align:center
...

{Type B} // fks. fejlsystem (liste over fejlkoder)
$empty_param:icon=doc_error;title_us=Empty parameter;title_dk=Tom parameter
$empty_folder:icon=doc_error;title_us=Folder is empty;title_dk=Mappen er tom
$invalid_password:title_us=Invalid password;title_dk=Ugyldig adgangskode;desc_us=..
$undefined_data:title_us=Undefined data;title_dk=Udefineret data;desc_us=..

Nu er det så at linjeskiftet erstattes med "§" :
$empty_param:icon=doc_error;title_us=Empty parameter;title_dk=Tom parameter§$empty_folder:icon=doc_error;title_us=Folder is empty;title_dk=Mappen er tom§$invalid_password:title_us=Invalid password;title_dk=Ugyldig adgangskode;desc_us=..§$undefined_data:title_us=Undefined data;title_dk=Udefineret data;desc_us=..§

På den måde kan det gives et "navn" så det starter med:
§B@errorcodes:$empty_param:icon=.....§$empty_folder:icon=.....§$invalid_password:icon=.....
§B@logcodes:$start_app:icon=.....§
§A@fonts:font.name:Tahoma§

Herefter er det så noget i den stil:
for i:=0 to count-1 do begin s:=strings[i];
if s<>'' then                        //beskyt kald af første tegn
  if s[1]='§' then                    //kald første tegn
  if s[3]='@' then begin              //kald tredje tegn
    dataType:=s[2];                    //find datatype fra andet tegn
    c:=ansiPos(':',s);                //find første kolon
    dataName:=copy(s,4,c-1);          //datanavn fra @ indtil kolon'et
    dataParams:=copy(s,c+1,length(s))  //parametrene er så efter kolon'et
  end
end;

Nu kan man sige focus(navn) // ligesom "select".
Så splitter den parametrene ved § til to lister (names,params:stringList)
(først var det jeg brugte: names:array of shortString;params:array of string)

Herefter lookAt(parameter)
for i:=0 to count-1 //og så hvis names[i]=parameter then begin result:=params[i];exit end

------------------------------------

Jeg kan evt sende et langt fra færdigt forsøg med en lille editor test.
Men det er sikkert noget være fusker-kode :)

Der ligger selve den unit med disse to klasser.
Jeg kan lave en datafil med alle typerne og smide med.
Avatar billede martinlind Nybegynder
01. september 2007 - 20:52 #23
De fleste af de componenter VCL'en har bruger en TList/StringList til et eller andet, feks. Lines i en memo, item i en combobox osv.

TList er et array af pointer en pointer er samme størelse som en integer/char så hvis du har en liste af Interger/char kan du bruge en TList i stedet for tstringlist
Avatar billede hrc Mester
01. september 2007 - 22:53 #24
Martin: I Objektorienteret programmering er der ikke noget der hedder pointere (det bør der i alt fald ikke være) og derfor skal man også prøve at undgå TListen. Især når dens næsten identiske fætter hedder TObjectList. De eneste (ret vigtige) forskelle er at data er typesikret og at de automatisk frigives når listen bliver det.

mbsnet: Efter at have kigget på din seneste kommentar melder spørgsmålene sig:
- Hvordan ser type C ud? Har et bud, men du glemte den.
- Hvorfor ikke bruge XML? Fylder det for meget?
- Kreerer du virkelig n antal objekter i starten af dit program, objekter som du først frigiver ved afslutning? Det er ikke sund programmering.
Avatar billede mbsnet Nybegynder
01. september 2007 - 23:04 #25
Martinlind> nu forstår jeg hvad du mener :)

Type C er korrekt.
værdi1
værdi2
værdi3
altså: værdi1§værdi2§værdi3

Det er kun hvis jeg har brug for indstillingerne hele tiden. mens programmet kører. Andre gange opretter/frigiver jeg "med det samme" inden i funktionerne / procedurerne. Kender ikke rigtig xml. Men jeg kan godt lide disse 3 typer. Mange ini-filer er jo eksempelvis "type a"
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester