Delphi ja muistinkäsittely

ihmettelijäXY

Terve!

Miten delphi käsittelee alla olevan sijoituksen,
siis ihmettelen kun first:llä ja secondilla on eri muistiosoitteet ja kuitenkin kun toisen arvoa muuttaa muuttuu se molempiin, sekä jos toisen näistä vapautaa, jää toinen muistiin ja delphi vapauttaa sen automaattisesti?

Osaako joku kertoa mitä tuossa siis tapahtuu? Kiitos!
...............................................
type
TObj = Class(TObject)
i : Integer;
end;
...
var
Fisrt, Second : TObj;
begin
Fisrt := TObj.Create;

// Varaako Delphi tässä kohtaa muistia itse oliolle Second
// ja vapauttaa sen automaattisesti?
Second := Fisrt;

Second.i := 5;
Fisrt.i := 6;
ShowMessage(IntToStr(Second.i)); // näyttää arvon 6
Fisrt.Free; // Miksi Second muuttujaa ei tarv. vapauttaa itse?
end;

10

594

    Vastaukset 10

    Anonyymi (Kirjaudu / Rekisteröidy)
    5000
    • ...

      Second := Fisrt; sijoittaa Second:iin Fisrt:in osoitteen. Erillistä oliota Second ei ole olemassa missään vaiheessa.

      • IhmettilijäXY

        Niin minäkin luulin, mutta jos vapautan First:n (First.Free;) niin miksi vielä tämän jälkeen pystyn käsittelemään Second:n kautta tätä muistia? Tämä ihmetyttää suuresti..


      • ...
        IhmettilijäXY kirjoitti:

        Niin minäkin luulin, mutta jos vapautan First:n (First.Free;) niin miksi vielä tämän jälkeen pystyn käsittelemään Second:n kautta tätä muistia? Tämä ihmetyttää suuresti..

        Koe 1:
        Fisrt.Free;
        Second.i:=11; // tulee virheilmoitus invalid pointer oper...


        Koe 2:
        Fisrt.Free;
        ShowMessage(IntToStr(Second.i)); // eri luku kuin alunperin sijoitettu


      • IhmettilijäXY
        ... kirjoitti:

        Koe 1:
        Fisrt.Free;
        Second.i:=11; // tulee virheilmoitus invalid pointer oper...


        Koe 2:
        Fisrt.Free;
        ShowMessage(IntToStr(Second.i)); // eri luku kuin alunperin sijoitettu

        CodeGear delphi 2007 pro.
        Ks. Alla oleva..Ei tule virhe ilmoitusta ja kaikki menee kuin pitää, ja mitään muisti vuotoa en havainnut...

        Onko kyse Delphin optimoinnista vai mistä, menee
        yli hilseen..


        procedure TForm1.Button1Click(Sender: TObject);
        var
        Fisrt, Second : TObj;
        begin
        Fisrt := TObj.Create;
        Second := Fisrt;
        Fisrt.Free;
        Second.i := 1234;
        ShowMessage(IntToStr(Second.i)); // näyttää arvon 1234
        end;


      • ...
        IhmettilijäXY kirjoitti:

        CodeGear delphi 2007 pro.
        Ks. Alla oleva..Ei tule virhe ilmoitusta ja kaikki menee kuin pitää, ja mitään muisti vuotoa en havainnut...

        Onko kyse Delphin optimoinnista vai mistä, menee
        yli hilseen..


        procedure TForm1.Button1Click(Sender: TObject);
        var
        Fisrt, Second : TObj;
        begin
        Fisrt := TObj.Create;
        Second := Fisrt;
        Fisrt.Free;
        Second.i := 1234;
        ShowMessage(IntToStr(Second.i)); // näyttää arvon 1234
        end;

        Laitoin tuon koodin isomman ohjelmakoodin sekaan (D5 ja D7) ja silloin tuli virheilmoitus, mutta tuo koodi yksinään ei tehnyt virhettä. D7:ssa virhe tuli vasta ShowMessagen jälkeen.


      • IhmettilijäXY
        ... kirjoitti:

        Laitoin tuon koodin isomman ohjelmakoodin sekaan (D5 ja D7) ja silloin tuli virheilmoitus, mutta tuo koodi yksinään ei tehnyt virhettä. D7:ssa virhe tuli vasta ShowMessagen jälkeen.

        Eli otsikon mukaan, olen samaa mieltä kuin sinä että tuo "Second" on pelkkä pointteri tuohon "First" olioon, eli oletko samaa mieltä että kääntäjä ei tässä tapauksessa ole vielä vapauttanut "First" muistialuetta ja siksi "joissain tapauksissa" siihen voidaan vielä viitata samassa funktiossa, vai onko käyttisksellä osuutta tuohon (windows xp)..
        ...
        Mutta kun katsoin tuon (First := Second) sijoituksen jälkeen kummankin osoitteen muistissa niin olivat eri alueella, erona tosin oli tuo 4 tavuinen int muuttuja(i)...???


      • ...
        IhmettilijäXY kirjoitti:

        Eli otsikon mukaan, olen samaa mieltä kuin sinä että tuo "Second" on pelkkä pointteri tuohon "First" olioon, eli oletko samaa mieltä että kääntäjä ei tässä tapauksessa ole vielä vapauttanut "First" muistialuetta ja siksi "joissain tapauksissa" siihen voidaan vielä viitata samassa funktiossa, vai onko käyttisksellä osuutta tuohon (windows xp)..
        ...
        Mutta kun katsoin tuon (First := Second) sijoituksen jälkeen kummankin osoitteen muistissa niin olivat eri alueella, erona tosin oli tuo 4 tavuinen int muuttuja(i)...???

        Fisrt.Free:n jälkeen muisti on vapautettu, mutta tuurilla sen käyttäminen voi vielä onnistua.

        CPU ikkunasta
        Fisrt := TObj.Create; eax=Fisrt
        Fisrt.i:=3; mov [eax 4],3
        Second := Fisrt; mov ebx,eax
        Fisrt.Free;
        Second.i := 1234; mov [ebx 4],$4d2 sama paikka kuin Fisrt.i


      • ihmettelijäXY
        ... kirjoitti:

        Fisrt.Free:n jälkeen muisti on vapautettu, mutta tuurilla sen käyttäminen voi vielä onnistua.

        CPU ikkunasta
        Fisrt := TObj.Create; eax=Fisrt
        Fisrt.i:=3; mov [eax 4],3
        Second := Fisrt; mov ebx,eax
        Fisrt.Free;
        Second.i := 1234; mov [ebx 4],$4d2 sama paikka kuin Fisrt.i

        Kiitos paljon perustellusta vastauksesta kaikkine viesteineen, tuo selvensi paljon..


      • Mika0800

        "Second := Fisrt; sijoittaa Second:iin Fisrt:in osoitteen. Erillistä oliota Second ei ole olemassa missään vaiheessa."

        Kirjoittaja on 100% oikeassa.

        Muistaakseni Delphissä voi itse määrittää olioluokalle poikkeuksellisen tavan varata muistia oletustavan sijaan.

        Olisiko ollut InitInstance ?

        Tuohon löydät hyvät ohjeent tästä kirjasta:

        http://www.bookplus.fi/product.php?isbn=9780672312847

        ISBN: 9780672312847

        Jos siis muokkaat olion muistitilanvaraustapaa siten, ettei siihen normaalista poiketen käytetäkään Delphin omaa GetMem:iä, vaan windowsin VirtualAlloc -funktiota (reserve, commit), ja vapautettaessa vain uncommit, mutta jätetään reserved -tilaan, niin silloin tuo First.Free -kutsun jälkeinen Second.i := 1234 aiheuttaa "Access violation" -virheilmoituksen.

        Delphin oma muistinvarausjärjestelmä vain peittää virheen näkyvistä, mutta virhe se silti on.

        Second := First -tyyppinen lause siis vain asettaa tosiasiassa 2 olio-osoitinta osoittamaan samaan olioon, ja ensimmäisen vapautus aiheuttaa sen, että toinen (tai itseasiassa molemmat, jos et itse aseta First := Nil tai FreeAndNil(First); ) osoitin osoittaa jo vapautettuun muistiin, eli ko. varausta ei enää virallisesti ole olemassa.

        Jos olisit tehnyt uuden muistinvarauksen heti tuon First.Free;n jälkeen, niin sen jälkeen tuo Second.i := 1234 olisi saattanut korruptoida mitä tahansa muuta tietoa, jota olisit tuohon uuteen muistivaraukseen tallentanut.

        Useammalla muuttujalla samaan olioon viittaaminen ei sinänsä ole kiellettyä, mutta vaatii erityistä huolellisuutta tehdä se oikein, muuten tuloksena on ohjelma, joka korruptoi muistia ja antaa siksi vääriä tuloksia, jumiutuu tai tekee muuta "mystistä".


      • Mika0800
        Mika0800 kirjoitti:

        "Second := Fisrt; sijoittaa Second:iin Fisrt:in osoitteen. Erillistä oliota Second ei ole olemassa missään vaiheessa."

        Kirjoittaja on 100% oikeassa.

        Muistaakseni Delphissä voi itse määrittää olioluokalle poikkeuksellisen tavan varata muistia oletustavan sijaan.

        Olisiko ollut InitInstance ?

        Tuohon löydät hyvät ohjeent tästä kirjasta:

        http://www.bookplus.fi/product.php?isbn=9780672312847

        ISBN: 9780672312847

        Jos siis muokkaat olion muistitilanvaraustapaa siten, ettei siihen normaalista poiketen käytetäkään Delphin omaa GetMem:iä, vaan windowsin VirtualAlloc -funktiota (reserve, commit), ja vapautettaessa vain uncommit, mutta jätetään reserved -tilaan, niin silloin tuo First.Free -kutsun jälkeinen Second.i := 1234 aiheuttaa "Access violation" -virheilmoituksen.

        Delphin oma muistinvarausjärjestelmä vain peittää virheen näkyvistä, mutta virhe se silti on.

        Second := First -tyyppinen lause siis vain asettaa tosiasiassa 2 olio-osoitinta osoittamaan samaan olioon, ja ensimmäisen vapautus aiheuttaa sen, että toinen (tai itseasiassa molemmat, jos et itse aseta First := Nil tai FreeAndNil(First); ) osoitin osoittaa jo vapautettuun muistiin, eli ko. varausta ei enää virallisesti ole olemassa.

        Jos olisit tehnyt uuden muistinvarauksen heti tuon First.Free;n jälkeen, niin sen jälkeen tuo Second.i := 1234 olisi saattanut korruptoida mitä tahansa muuta tietoa, jota olisit tuohon uuteen muistivaraukseen tallentanut.

        Useammalla muuttujalla samaan olioon viittaaminen ei sinänsä ole kiellettyä, mutta vaatii erityistä huolellisuutta tehdä se oikein, muuten tuloksena on ohjelma, joka korruptoi muistia ja antaa siksi vääriä tuloksia, jumiutuu tai tekee muuta "mystistä".

        Tuo mainitsemani "delphi developer's guide" on ihan hyvä kirja, mutta enpä voi taata, etträ siitä löytyisi esimerkkiä InitInstance:n käytöstä.

        Tuo mainitsemani InitInstance on FreeInstancen vastinpari, ja FreeInstancen käytöstä löytyy esimerkki seuraavasta kirjasta:

        "Secrets of Delphi 2", kirjoittaja Ray Lischner.

        viite:
        http://www.tempest-sw.com/secrets/

        sivulta 592,luvusta "19: Heaps of Secrets".


        Siinä on override -määreellä määritelty poikkeusluokan FreeInstance -metodi tyhjäksi metodiksi.

        Seuraus: Kun poikkeuskäsittelyssä Delphi yleensä vapauttaa poikkeusluokann ilmentymän (eli objektin) automaattisesti, kun poikkeus on käsitelty, niin FreeInstance -metodin korvaaminen tyhjällä metodilla aiheuttaa sen, ettei poikkeusobjektia vapauteta. Näin se voidaan aina uudelleen nostaa pelkällä raise:lla ilman create:a, kun sitä ei koskaan vapauteta.

        Se on siis luotu unitin initialization -lohkossa.

        Vastaavalla tavalla voisi siis luokan sekä InitInstance että FreeInstance -metodit korvata sellaisilla,jotka ohittavat Delphin omat GetMem/FreeMem ja korvaavat ne windowsin VirtualAlloc / VirtualFree -funktioilla.

        Halutessa voi esim.tehdä osittaisen VirtualFreen siten, että fyysinen muisti vapautuu, mutta muisti(osoite)avaruus ei. Tällöin muisti jää (reserved, uncommitted) -tilaan.

        Tällöin yritys viitata ko. muistiin aiheuttaa "access violation" -poikkeuksen.

        sopivia {$ifdef muistivirheenjaljitys] ...koodia... {$endif}

        -lauseita hyödyntäen homman voi tehdä niinkin, että kun muistivirheet on etsitty ja korjattu, niin muuttamalla:

        {$define muistivirheenjaljitys}

        ->

        {.$define muistivirheenjaljitys}

        ja uudelleenkääntämälää, poistuvat omat muutokset muistinkäsittelyssä, ja käytetään jälleen delphin omaa oletusmuistimanageria.


    Ketjusta on poistettu 0 sääntöjenvastaista viestiä.

    Luetuimmat keskustelut

    1. Mikä sun salaisuus on,kun näytät niin nuorelta..

      Vaikka oot jo noin vanha!?
      Ikävä
      128
      2056
    2. MiltäKaivattusi

      Näyttää? !
      Ikävä
      51
      989
    3. Perhoseni (miehelle)

      Miksi et usko, että mun rakkaus sinuun on aitoa ja vilpitöntä? Tai että se oli jo silloin? Miksi ajattelet, ettet ole r
      Ikävä
      158
      868
    4. Myönnetään, tunnen lämpimiä tunteita kohtaasi

      Vaikutat tosin liian hyvältä ollaksesi totta. Komeita miehiä on maailma pullollaan mutta sinussa on jotain.....
      Ikävä
      50
      766
    5. Mitä meidän välillämme

      On käynyt näiden vuosien aikana?
      Ikävä
      77
      710
    6. Olen tavattavissa

      tänään klo 17-02 siinä ravintolassa. Tulethan sinäkin?
      Ikävä
      53
      627
    7. Uskaltaisitko

      Tavata kaivattusi tässä tilanteessa?
      Ikävä
      67
      626
    8. Halaus juuri sinulle

      Kaikki järjestyy kyllä. Luota vain. ❤️🫶
      Ikävä
      59
      616
    9. Onko Sofia jälleen jätetty?

      Moni asia viittaisi siihen, että hän on jälleen sinkku.
      Kotimaiset julkkisjuorut
      144
      606
    10. Rekat seisovat dieselin hinnan takia . Ala ei kestä tällaista hintatasoa, sanoo yrittäjä .

      EU:n kallein diesel on kova paikka kuljetusalalle. Ajoja on jätetty ajamatta kannattavuus­ongelmien vuoksi, sanoo alan e
      Kajaani
      131
      566
    11. Mies, näetkö minut myös

      Seksuaalisena ihmisenä ja naisena? Haluatko minua seksuaalisesti? Vai olenko mielestäsi tyttönen?
      Ikävä
      20
      520
    12. Kuka se on

      Kuhmon komein aikamies?
      Kuhmo
      6
      504
    13. Uskallatko paljastaa

      Millä nimellä löydyn puhelimestasi?
      Ikävä
      52
      503
    14. Voiko se ikinä toimia

      Voiko meistä ikinä tulla mitään? Näin kauan aikaa on kulunut ja mitään ei tapahdu... En usko, että sinä mietit minua het
      Ikävä
      32
      498
    15. Kuollut teini Kajaanissa

      Kuulemma sellaista huhua liikkeessä?
      Kajaani
      4
      489
    16. Voin tulla

      Sisustamaan sulle 🤭
      Ikävä
      55
      488
    17. Meneekö unohtamis

      Projektisi hyvin??
      Ikävä
      34
      487
    18. Nainen, mitä mieltä olet kodittomista?

      Ja heistä jotka eivät kykene huolehtimaan asioistaan, itsestään eikä terveydestään? Miten heidän kanssaan tulisi toimia?
      Ikävä
      118
      486
    19. Totta on asia. Jeffrey Cohen on jättänyt Sofian.

      Vaimon viesti on paljastanut totuuden.
      Kotimaiset julkkisjuorut
      152
      469
    20. Mitä jos...

      Susta tykätään poikana enemmän, kun tyttönä? Miten asian käsittelet tai otat tiedon vastaan? T nainen gubetellija herät
      Sinkut
      142
      463
    Aihe