Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C#: Unity ja GC alloc

tkok [08.04.2015 11:45:41]

#

Moi, koodini varaa kiloittain GC alaista muistia. Onko putkalaisilla ideoita miten tästä pääsisi eroon?

Ohjelmassa on iso lista objecteja (yli 10k kpl) ja käyn ne objectit for-loopilla läpi joka framessä. Ne mitkä niistä objecteista näkyy näytöllä pyydän antamaan vertice-, triangle- ja vertexcolor-datat sitten otan datat vastaan ja Appendaan niitä varten varattuihin List-listoihin. (listat on aluksi Clearattu). Sitten kun on noi kaikki käyty läpi ja listat on valmiina niin pistän datan meshiin. Mesh kuitenkin ottaa vastaan vain Array-tyyppiä, ei List tyyppiä, joten käytyän List-listan .ToArray() funktiota. Tämä funktio varaa kuitenkin kiloittain GC allocin alaista muistia. Onko tätä mahdollista tehdä tehokkaammin GC allocin näkökulmasta? Yksi ongelman solmuista on se että joka frame näihin listoihin tulee vaihteleva määrä dataa.

Vector3 _pos = transform.position;
vertices.Clear();
triangles.Clear();
vertexColors.Clear();
int triIndexOffset = 0;
for (int x = 0; x < tilesCount; x++)
{
    float newT = Mathf.Min(t / offsetOfAnimations.Evaluate(x / (float)tilesCount), 1f);
    //Do clipping
    if (_clipping)
    {
        float dis = GetClippingDistance(tiles[x].Center + _pos);
        float scale = Mathf.Max(0, (_clippingRange - dis) / _clippingRange);
        //print("scale: " + scale + " dis: " + dis);
        if (scale <= 0) continue;
        tiles[x].scaleX = tiles[x].scaleY = scale;
    }

    vertices.AddRange(tiles[x].GetVertices(newT));
    triangles.AddRange(tiles[x].GetTriangles(++triIndexOffset * 4));
    vertexColors.AddRange(tiles[x].GetColors(newT));
}

mesh.triangles = new int[0];
//Tästä tulee GC allocia kiloittain:
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.colors32 = vertexColors.ToArray();

groovyb [08.04.2015 15:49:22]

#

Voisit kokeilla asettaa listat nulliksi käytön jälkeen, ja luo listat uudestaan metodiin saavuttaessa.

Vector3 _pos = transform.position;
List<Vector3> vertices = new List<Vector3>();
int triIndexOffset = 0;
for (int x = 0; x < tilesCount; x++)
{
    float newT = Mathf.Min(t / offsetOfAnimations.Evaluate(x / (float)tilesCount), 1f);
    //Do clipping
    if (_clipping)
    {
        float dis = GetClippingDistance(tiles[x].Center + _pos);
        float scale = Mathf.Max(0, (_clippingRange - dis) / _clippingRange);
        //print("scale: " + scale + " dis: " + dis);
        if (scale <= 0) continue;
        tiles[x].scaleX = tiles[x].scaleY = scale;
    }

    vertices.AddRange(tiles[x].GetVertices(newT));
}

mesh.triangles = new int[0];
//Tästä tulee GC allocia kiloittain:
mesh.vertices = vertices.ToArray();
vertices = null;

tkok [08.04.2015 16:18:05]

#

Kun lista on funktion sisäisessä scopessa eli ehdotuksesi kanssa:

List<Vector3> vertices = new List<Vector3>();

GC muistia varataan myös kun listaa pidennetään, kun jos se on ulkopuolella niin Clearin jälkeen lista säästää kapasiteettinsa eli varaamansa muistialueen. Eli ehdotuksessasi tuo ToArrayn varaa edelleen omansa, mutta sen lisäksi AddRange funktio varaa muistia jopa 3 kertaa enemmän joka frame.

feenix [08.04.2015 17:33:42]

#

tkok kirjoitti:

Kun lista on funktion sisäisessä scopessa eli ehdotuksesi kanssa – – GC muistia varataan myös kun listaa pidennetään.

Jep, tuota ei tosiaan kannata tehdä. Listan "tyhjennys" on nopea operaatio, sillä määritellään vain rajat osoittamaan se tyhjäksi. Uuden luomisessa jos ei kerro haluttua kokoa joutuu lista suurentamaan itseään jatkuvasti.

Eipä tuota oikein voi mitenkään estää. Jos kerran data on dynaamista, se vaatii dynaamista muistia.

tkok [08.04.2015 19:26:05]

#

feenix kirjoitti:

Eipä tuota oikein voi mitenkään estää. Jos kerran data on dynaamista, se vaatii dynaamista muistia.

Samaan lopputulokseen tulin päivän päätteeksi.

Osittaisena ratkaisuna voisi Vertex ja Color tauluja pitää vakiokokoisina, niin että analysois noiden objektien paikat ja laskisi siitä paljonko maksimissaan tarvitsee kerralla verticejä ja varaa sen mukaiset isot Arrayt. Sitten jos jokin objecti ei ole näkyvissä niin jättää triangle datasta sen pois, jolloin kaikkia verticejä ja niiden värejä ei rendata laisinkaan. Saattaa tosin olla että tämä teoreettinen maksimi kokoinen taulu on niin iso että ylimääräisien pisteiden kopiointi rasittaa pelin pyörimistä kaikissa tilanteissa ja kuitenkin triangle taulun muutokset varaavat GC muistia.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta