Pagina 2 di 2 primaprima 1 2
Visualizzazione dei risultati da 11 a 15 su 15

Hybrid View

  1. #1
    Ragazzi, mi sembra che stiate facendo su un "rebelòtt"

    La questione è molto più semplice:
    • se A è un reference type (ovvero, è una classe, non una struct o un tipo primitivo), tutte le volte che dichiari una variabile di tipo A in realtà stai dichiarando un riferimento ad A; puoi pensare ad un riferimento come ad un "filo" che collega il nome della tua variabile all'oggetto (=istanza) vero e proprio;
    • le istanze degli oggetti stanno nell'heap gestito; di base gli oggetti vengono costruiti (e la memoria viene allocata) solo quando c'è una "new"; se tu scrivi
      codice:
      A myA = new A();
      stai facendo tre cose distinte e molto diverse:
      • A myA dichiara un reference locale ad A, allocato sullo stack;
      • new A() crea nell'heap un'istanza di A
      • = fa puntare il riferimento myA all'oggetto appena creato sull'heap.

    In generale, le variabili-riferimento e gli oggetti veri e propri allocati sull'heap non sono accoppiati in maniera stretta; se un riferimento esce di scope, oppure se crei un altro riferimento (=dichiari un'altra variabile) che punta allo stesso oggetto (A anotherA=myA;), all'oggetto vero e proprio non importa niente - lui sta lì per i fatti suoi sull'heap, dei riferimenti che puntano a lui non gliene frega niente.

    Se tutta la questione terminasse così, ci sarebbe un serio problema: dato che l'uscita di scope dei reference non ha alcun effetto sugli oggetti sull'heap, dopo un po' l'heap si riempirebbe di spazzatura, ovvero di oggetti che non servono più, non essendo più raggiungibili tramite reference da parte del programma.
    Qui entra in scena il garbage collector; quando il GC ne ha voglia, provvede ad esaminare tutto l'albero di riferimenti, segnandosi quali oggetti sono ancora raggiungibili da parte del programma (e quindi sono in uso); alla fine del procedimento, provvede ad eliminare quelli che non sono stati marcati, dato che sono tutta roba che non serve più (dato che il programma non vi può accedere tramite riferimenti, significa che è tutta roba non più usata).

    In un certo senso, puoi vedere gli oggetti come dei palloncini e i riferimenti come dei fili; quando crei un nuovo oggetto, gonfi un palloncino, e assegnando il risultato della new ad una variabile ci leghi il suo filo; quando lo memorizzi in una collection, lo passi a funzioni, ... non stai facendo altro che legarci dei nuovi fili che passi ad altri pezzi del tuo codice. Ogni volta che un reference esce di scope (o ci viene assegnato null, oppure viene fatto puntare ad un altro oggetto), viene tagliato il suo filo (eventualmente ri-legandolo ad un altro oggetto se stai riassegnando il reference), e quando non c'è più nessun filo il palloncino vola via. Il GC non è altro che la "contraerea" , che, per evitare che il cielo si riempia di palloncini vecchi, di tanto in tanto spara pallini e abbatte i palloncini senza fili.

    Tornando quindi al tuo codice, anche l'hashtable in realtà è una hashtable di riferimenti; se rimuovi un elemento dalla hashtable, stai uccidendo un reference, e l'oggetto (palloncino) a cui puntava, se non ha altri riferimenti (fili), diventa passibile di garbage collection (contraerea ). Quando tu rimpiazzi un elemento nella hashtable, quello che fai è:
    • tagliare il filo al vecchio palloncino; se non ci sono altri palloncini, questo vola via, e tra un po' potrebbe essere abbattuto;
    • gonfiare un nuovo palloncino (nel tuo caso più grosso);
    • legare il nuovo palloncino allo stesso gancio a cui era attaccato il vecchio.

    (in realtà anche la hashtable è un oggetto a cui c'è un riferimento come membro della classe, per cui in realtà sono palloncini legati ad altri palloncini che sono ancorati a terra mediante variabili sullo stack o variabili globali, ma la metafora inizia ad incasinarsi un po' troppo )

    In tutto questo, come puoi vedere non viene espansa "memoria vecchia", ma piuttosto vengono rilasciati vecchi oggetti e allocati di nuovi. La chiave per evitare di sprecare memoria ovviamente è non mantenere riferimenti "di lunga durata" ad oggetti che non servono più - una volta rimosso un oggetto dalla hashtable, ad esempio, se hai altre variabili che puntano al "vecchio" oggetto può convenire impostarle a null (anche se va detto che la situazione non è così tragica come la dipingeva rsdpzed, di norma dei riferimenti locali ad una funzione è difficile che diano problemi, visto che spariscono appena escono di scope; quello che importa davvero sono riferimenti a livello di classe o memorizzati in altri oggetti).

    ---

    Per inciso, dando un'occhiata al tuo codice mi sembra ci sia una certa confusione su static e compagnia - nello specifico, inizializzi variabili static dentro al costruttore d'istanza in linea di massima nella tua classe non credo ci dovrebbe essere alcunché di static.
    Ultima modifica di MItaly; 03-11-2013 a 15:55
    Amaro C++, il gusto pieno dell'undefined behavior.

  2. #2
    Utente di HTML.it L'avatar di rsdpzed
    Registrato dal
    Aug 2001
    Messaggi
    764
    Allora lasciamo da parte il discorso legato alla x perchè altrimenti ci incasiniamo.

    1) Si. Ora l'hashtable ha solo due elementi.

    2) Viene creato un nuovo elemento, della giusta dimensione, con chiave "B" e collegato all'hastable. Il fatto che la chiave sia una usata precedentemente da un altro elemento è del tutto irrilevante. Questo elemento appena creato è del tutto nuovo e viene posizionato in un area di memoria completamente diversa dal precedente. La somma delle dimensioni però è quella che ci si aspetterebbe da quella risultante dall'eliminazione di un elemento di peso w e l'aggiunta di uno di peso k.

    Alla luce di questo è chiaro che nella tua soluzione le dimensioni dell'hastable planets aumenta e diminuisce correttamente in base all'occorrenza perche ad ogni ricalcolo elimini i pianeti near che si sono allontanati, li reinserisci come far e viceversa.

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

    Questo significa che il programma funziona e fa quello che deve fare.
    Solo che se chiedi di capire esattamente cosa accade e avere la padronanza del codice allora non si puo prescindere dal discorso fatto nei post precedenti.
    Premetto che per come è adesso nonostante l'imperfezione, il codice dovrebbe comportarsi bene anche in situazioni di stress. Va bene, ma solo perche dopo l'unsolve H1 termina. Immagina se dopo l'unsolve dentro H1, quando la x è ancora accessibile, tu avessi bisogno di mettere delle operazioni che necessitino di tanta memoria. Avresti problemi perche hai appena eliminato un near rimpiazzandolo con un far ma la memoria di quel near non puo essere rilasciata in quanto è ancora referenziata da x. Planets è a tre pianeti ma la x punta ancora al pianeta near che dovresti/vorresti aver eliminato con unsolve. In questo contesto ci sono quattro pianeti: i tre in hastable delle corrette dimensioni piu un near appeso alla x e che occupa memoria.
    L'altro problema è: che cosa succederebbe se dopo l'unsolve tu utilizzassi per sbaglio quella x legata ad un pianeta che in hastable si trova in stato di far ma che con la x si trova in stato di near? sarebbe lecito utilizzare questo pianeta di troppo e che verrà eliminato comunque alla fine della funzione? credo la risposta sia no.

    Fai bene a porti il problema e a voler approfondire una cosa di questo genere perchè i migliori bug che mente informatica sia stata in grado di concepire (quelli che non si vedono all'inizio, che vengono fuori quando si aggiunge codice apparentemente innocuo e che accadono una volta si e 100 no) sono proprio legati a cose come questa.

  3. #3
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308
    Fantastica la storia dei palloncini e della contraerea. Valeva la pena avere questi dubbi.... me la sono scritta nel manuale di C#.

    Per inciso, dando un'occhiata al tuo codice mi sembra ci sia una certa confusione su static e compagnia - nello specifico, inizializzi variabili static dentro al costruttore d'istanza in linea di massima nella tua classe non credo ci dovrebbe essere alcunché di static.
    Detto tra noi, il programma funziona alla grande ma molte cose le ho scritte per intuito. E' da poco tempo che studio il C# (figurati Xna) e non scherzavo quando dicevo che molte cose le uso anche se non le ho capite a fondo. In particolare le "public static" della classe My, scritta nel file My.cs, se non fossero static, non sarebbero accessibili alle varie strutture dei mondi ognuna delle quali è scritta in un file xxx.cs a parte. Faccio un esempio.
    Se mi avvicino troppo ad un oggetto SphWorld questo deve trasformarsi in un oggetto SphHWorld dove 'H' sta per Heightmap (SphWorld invece descrive una "palla da golf", piccola, leggera, nuda e cruda.
    Si, ma di quanto mi devo avvicinare? Ogni tipo di "mondo" ha la sua distanza critica detta EHorizon (orizzonte degli eventi). Ecco la parte iniziale della struttura SphWorld, scritta nel file SphWorld.cs:

    codice:
        public struct SphWorld
        {
            //campi di coerenza
            public Color Color;
            public float Density;
            public Texture2D HeightmapN, HeightmapE, HeightmapS;
            public float Hfactor;
            public Vector3 Inclination;
            public bool IsComa;
            public Vector3 Location;
            public float LocalGFactor;
            public Vector3 Rotation;
            public float Size;
            public Texture2D Texture;
            public Vector3 Velocity;
            //campi derivati
            public VertexPositionNormalColor[] vertices, AbsV;
    #if OLD16
            public System.Int16[] indices;
    #else
            public int[] indices;
    #endif
            public float Ehorizon;
            public float FarD;
            public float Mass;
            public float GuardianIndex;
            public float RemoteIndex;
            public static int n, Tv, Tn;
            public static float Hmod;
            public SphWorld(Color C, float D, float F, Texture2D HN, Texture2D HE, Texture2D HS, float Hf, Vector3 I, bool IC, Vector3 L, Vector3 R, float S, Texture2D T, Vector3 V)
            {
                Color = C;
                Density = D;
                HeightmapN = HN;
                HeightmapE = HE;
                HeightmapS = HS;
                Hfactor = Hf;
                Inclination = I;
                IsComa = IC;
                Location = L;
                LocalGFactor = F;
                Rotation = R;
                Size = S;
                Texture = T;
                Velocity = V;
                Ehorizon = My.Efactor * S;
                ......
    
    Come si vede ci sono campi "di coerenza" (questa definizione è legata ad un aspetto molto complesso del programma, ma in sintesi sono i parametri che compaiono nel costruttore) e "campi derivati" (non presenti nella firma del costruttore ma che vengono calcolati dai campi coerenti). In particolare l'EHorizon di un oggetto SphWorld è precisamente il suo Size moltiplicato per un fattore che voglio impostare dal file principale My.cs. Questo fattore è dichiarato insieme al suo valore all'inizio della classe My:

    codice:
       public class My : Microsoft.Xna.Framework.Game
        {
            //Generals          
            public static GraphicsDeviceManager Graphicsdevicemanager;
    #if WIDE
            public static int RisX, RisY;
    #else
            public static int RisX = 1350;
            public static int RisY = 650;
    #endif
            public static Effect ShaderColor, ShaderLightColor, ShaderLightTexture, ShaderTexture;
            public static Matrix View, Projection, World = Matrix.Identity;
            public static Vector3 LightDirection;
            public static SpriteBatch Spritebatch;
            public static Texture2D Background;
            public static SpriteFont Spritefont;
            public static Random Rnd = new Random((int)DateTime.Now.Ticks);
            public static RasterizerState Rasterizerstate; //per il billboarding
            //BUFFERS
            public static VertexBuffer Vertexbuffer;
            public static IndexBuffer Indexbuffer;
            //System Gravity  
            public static float D = 1f;
            public static float Gfactor = 0.001f;//attenuatore gravità locale su Discovery (default: 0.001f)
    #if S
            public static float R = 60000f;
            public static int n = 4;
            public static float Vn = 100f;
            //-------------Derived----------------
            public static float G;
            public static float M;
    #elif T
            public static int n = 2;
            public static float Pn = 5f;
            public static float Vn = 80f;
            //-------------Derived----------------
            public static float G;
            public static float R;
            public static float M;
    #endif
    
            //Factors & Constants
            public static float Q1 = 100f;
            public static float Q2 = -100f;
            public static int MaxIC = 65535;
            public static string ColorMode = "Reverse";//Color - Scale - Reverse
            public static int g0 = 0;//Min. black
            public static int Efactor = 2;
             ......
    Una dichiarazione inizialmente scritta così:
    codice:
    public int Efactor = 2;
    
    non era visibile dalla struttura SphWorld!


    !
    Ultima modifica di escocat; 03-11-2013 a 18:25

  4. #4
    se non fossero static, non sarebbero accessibili alle varie strutture dei mondi ognuna delle quali è scritta in un file xxx.cs a parte
    Probabilmente dagli altri mondi cerchi di accedere ai metodi & co. in questione tramite il nome della classe e non tramite l'istanza specifica dell'oggetto...
    Amaro C++, il gusto pieno dell'undefined behavior.

  5. #5
    Utente di HTML.it L'avatar di escocat
    Registrato dal
    Feb 2012
    Messaggi
    308
    La distanza critica EHorizon è una proprietà di ciascun oggetto istanziato da un tipo e dipende dal suo Size: ogni oggetto dello stesso tipo ha lo stesso EHorizon; ma il fattore mediante il quale viene calcolato - cioè che esprime "di quanto dipende dal Size" - non è una proprietà dell'oggetto di quel tipo ma di OGNI oggetto di OGNI tipo, cioè è una proprietà della classe più generale che il programma contiene, ovvero My. Per questo motivo - forse - è giusto che sia 'static'. Comunque mettetevi nei panni di uno che fino a 3 mesi fa lavorava ancora col VB5....

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2026 vBulletin Solutions, Inc. All rights reserved.