Search Unity

What happend to those parameters?

Discussion in 'Scripting' started by Shayke, Jun 7, 2018.

  1. Shayke

    Shayke

    Joined:
    Dec 8, 2017
    Posts:
    352
    Hi, i have an endless game and i noticed that after approximatley 50 stages on mobile or 100 or computer it becomes slower.
    I don't see that on the profiler so my guess was maybe my script has some problems.
    Everytime i hit the brick i have a new number that i use.(several times)
    For example:
    float Random = random.range(0,1);

    So my question is:
    Everytime that i use this command it makes me another float or it reuse it?
    Maybe it's one of the causes for making my game heavy.
    And i use destroy and inst all time so my game did not become heavier with objects.
     
  2. newjerseyrunner

    newjerseyrunner

    Joined:
    Jul 20, 2017
    Posts:
    966
    If will create a new float on your stack, which will be rolled back as soon is it goes out of scope. This is automatically done via the compiler.

    Have you profiled your memory? The symptoms do seem to point towards a memory leak.
     
  3. Shayke

    Shayke

    Joined:
    Dec 8, 2017
    Posts:
    352
    Can you tell what is the problem?
    [ View attachment 282129
     
  4. Shayke

    Shayke

    Joined:
    Dec 8, 2017
    Posts:
    352
    upload_2018-6-7_17-45-59.png

    Edit:
    The whole game doesnt become slower, just when i hit the brick.(from time to time it becomes slower)
    this is the part when i touch the brick:
    Code (CSharp):
    1.     public void OnTriggerEnter2D(Collider2D other)
    2.     {
    3.         if (other.CompareTag("Ground"))  //Open new Brick with option to troophy
    4.         {
    5.             if (MyCol.enabled)
    6.             {
    7.              
    8.                 transform.SetParent(other.transform);
    9.                 LastPosition.transform.position = transform.position;
    10.                 LastPosition.transform.SetParent(other.transform);
    11.          
    12.                 LastPosition.transform.position = Vector3.Lerp(LastPosition.transform.position, other.transform.position, 20 * Time.deltaTime); //prevent death rehearsal
    13.                 rb.velocity = new Vector3(0, 0, 0);
    14.                 if (LastBrick != other.gameObject) // If im standing on a new brick, so do something
    15.                 {
    16.                     if (Pitcher >= 1.15f) {
    17.  
    18.                         AM.Play("Extra"); AM.sounds[1].pitch = 0.95f; Pitcher = 0.95f; CountPitcher = -1;
    19.                         GameObject con = Instantiate(Confetti, transform.position + Vector3.up*10 + Vector3.right*2, Quaternion.identity);
    20.                         Destroy(con, 4);
    21.                     }
    22.                     else
    23.                     {
    24.                         AM.Play("Complete");
    25.                     }
    26.                     AM.sounds[1].pitch += 0.05f;
    27.                     Pitcher += 0.05f;
    28.                     CountPitcher++;
    29.                     UpdateComboBar();
    30.                     if (Vibrate)
    31.                     {
    32.                         Handheld.Vibrate();
    33.                     }
    34.                     FakeHP = 10; // FakeHP its for testing how much times the player on the edge and then push him left.
    35.                                  //  Invoke("NewDestroy", 3); // after Jump to new brick, destroy the last one.
    36.                     StartCoroutine(LastBrick.GetComponent<BrickText>().SelfDestroy());
    37.                     BeforeLastBrick = LastBrick;
    38.                     LastBrick = other.gameObject; //Set the current brick
    39.                     BrickLevel++;
    40.                     ObstacleIntensity += 0.01f;
    41.                     BrickLevelText.text = "Level: " + BrickLevel.ToString();
    42.  
    43.                     int RandomBrick = Random.RandomRange(0, NextBrick.Length); // Which Brick its gonna be
    44.                     if (RandomBrick == 3 && ObstacleIntensity < 0.3f) { RandomBrick = 0; } // If its not on hard mode so set normal brick instead of moving brick.
    45.                     ExtraDistance = 0;
    46.  
    47.                     if (other.name == "Big Fat Brick(Clone)" || RandomBrick == 1) { ExtraDistance = 2f; }// If it equals to the big fat brick so add Extra Distance;
    48.                     if (other.name == "Big Fat Brick(Clone)" && RandomBrick == 1) { ExtraDistance = 4f; }
    49.  
    50.                     float RandomX = Random.Range(3.5f + ExtraDistance, 4.5f + ExtraDistance); //Where the next Brick gonna be
    51.                     float RandomY = Random.Range(-2, 3); //Where the next Brick gonna be
    52.                     Vector3 TheOffset = new Vector3(1.4f * RandomX, 1.4f * RandomY, 0);
    53.  
    54.                     if (!ChallengeMode)
    55.                     {
    56.                         GameObject NewOne = Instantiate(NextBrick[RandomBrick], LastBrick.transform.position + TheOffset, Quaternion.identity);  // Instantiate the brick
    57.                         int RandomTroophy = Random.Range(0, 4); // Chance of 25% to get troophy;
    58.                         if (RandomTroophy == 3)
    59.                         {
    60.                             RandomTroophy = Random.Range(0, Troophy.Length); //Here i use the same random to test what troophy gonna be.
    61.                             GameObject Tro = Instantiate(Troophy[RandomTroophy], LastBrick.transform.position + TheOffset + Vector3.up * 5.9f, Quaternion.identity, NewOne.transform);
    62.  
    63.                         }
    64.  
    65.  
    66.                         if (RandomBrick != 2)
    67.                         {
    68.                             float RandomObstacleChance = Random.RandomRange(ObstacleIntensity, 1);
    69.                             if (RandomObstacleChance > 0.9f) // The chance slightly raise.
    70.                             {
    71.                                 int RandomObs = Random.Range(0, Obstacles.Length);
    72.                                 int RandomDir = Random.Range(-1, 2);
    73.  
    74.                                 GameObject ObstaclePrefab = Instantiate(Obstacles[RandomObs], LastBrick.transform.position + TheOffset + Vector3.up * 6.3f + (Vector3.right * RandomDir), Quaternion.identity, NewOne.transform);
    75.  
    76.                             }
    77.                         }
    78.                     }
    79.                 }
    80.                 else { AM.sounds[1].pitch = 1; Pitcher = 1; CountPitcher = 0; UpdateComboBar(); }
    81.                 AM.updateSound();
    82.                 if (ChallengeMode)
    83.                 {
    84.                     GameManager.ChallengeText.text = "Level: " + BrickLevel + "/" + GameManager.HowManyLevels;
    85.                 }
    86.                 other.GetComponent<Animator>().Play("Whitening");
    87.                 GameObject Particles = Instantiate(Land, GroundCheck.transform.position + Vector3.up / 3, Quaternion.identity);
    88.                 FakeHP -= 1; if (FakeHP < 0) { rb.velocity = new Vector3(-2, 5, 0); FakeHP = 10; } // If im on the edge and cant get away
    89.                 Destroy(Particles, 2);
    90.             }
    91.         }
     

    Attached Files:

    Last edited: Jun 7, 2018
  5. Shayke

    Shayke

    Joined:
    Dec 8, 2017
    Posts:
    352
    bump
     
  6. newjerseyrunner

    newjerseyrunner

    Joined:
    Jul 20, 2017
    Posts:
    966
    I would like to point out that Destroy does not unallocated the memory. C# is a managed language, so the garbage collector is what's actually responsible for freeing memory, but it should run fairly often. Notice how your GC memory slowly increases, then drops all at once.

    What happens if instead of instantiating and destroying objects, you pool them?

    Also, how many audio sources do you have playing at once? I've noticed that for some reason when I have a lot of audio sources playing at once, my frame rate suffers.

    I think it's more likely something else that's going on rather than memory. Memory leaks don't really cause slowdown until you have to start using virtual memory. I think you may have to simply comment everything out, make sure you don't experience the slowdown, then bit by bit uncomment the code until you find the offender.
     
  7. Shayke

    Shayke

    Joined:
    Dec 8, 2017
    Posts:
    352
    I think i have no choise but to pool like you said.
    I use maximum 2 sounds together.
    But more important to me is to understand why, can you give me an example for what is garbage collector and how can i ger rid of it?
     
  8. Shayke

    Shayke

    Joined:
    Dec 8, 2017
    Posts:
    352
    Btw what is this 384 bits that i have on Gui.Repaint?
     
  9. Shayke

    Shayke

    Joined:
    Dec 8, 2017
    Posts:
    352
    Any ideas?
     
  10. dadude123

    dadude123

    Joined:
    Feb 26, 2014
    Posts:
    789
    That's just some editor allocations. They're ~300 bytes are extremely small, and those allocations won't be there in a full build of the game.
    "GUI" is the old "immediate mode" gui code that is only used by the editor nowadays.

    That's a topic that has been discussed to death and back over the years.
    I'll give you a quick run down, but there are literally tens or even hundreds of forum posts discussing the GC, how to avoid it, what it does, its implications for development and so on...

    Long story short:
    You allocate objects in your code either directly by using "new SomeClass()" if "SomeClass" is a reference type, that means "class". If its a "struct" then no direct allocations happen.

    There are also indirect allocations that can happen sometimes. For example if you do
    new List<int>() you directly allocate space for the list first.
    But when you add too many elements (more than 4) then the list resizes it internal array to become twice as big to fit the new data and some more. That's an indirect allocation, because you calling List<>.Add does something that requires more memory..

    Another example is strings, which cannot be ever changed.
    string name = "abc" + someOtherString; // Will allocate a new string that is a combination of both
    name += "asdasdasdad"; // Will also create a new string, discard the old string, and put the new (combined) string into the variable, thus allocating, and generating garbage (the old string before the modification will be garbage collected).

    Then you also have "hidden" allocations. Those include "boxing", like this:
    object x = 5; // will box 5 into an object

    and advanced stuff like capturing variables into lambda expressions...

    Some quick hints:
    - Allocations are not what you are concerned about. Instead you are concerned about allocating stuff that you eventually stop using. For example calling Destory() on some gameobject means all the c# allocations that have happened for it have now "gone to waste" essentially, the GC has to clean that stuff up later...

    - To keep GC to a minimum you can pre-allocate stuff, use pooling for gameobjects, classes, ...

    - Some garbage is simply unavoidable (when you don't have the code for some library for example). And other times it would be so complicated or tedious to remedy all generated garbage that it is totally not worth it.

    - In some situations you are able to just not care. For example some systems in my game are very rarely used and situational (the level and script editor). There it's not worth fixing any wasteful allocations until it becomes a problem since level editting is very slow-paced anyway, and a short 100ms lag every minute or so won't bother anyone anyway.
     
  11. Shayke

    Shayke

    Joined:
    Dec 8, 2017
    Posts:
    352
    Wow did not know that.
    So destroy is actually not expensive just at the moment but also after.
    I should have known that before i built my game but never too late to learn more.
    And what can be a solution to the string issue?
    And lets say i want to make an endless game like this one:

    It would be much harder to make a pool instead of Instantiate and destroy.
     
  12. dadude123

    dadude123

    Joined:
    Feb 26, 2014
    Posts:
    789
    Yes, that's why pooling is so effective, you get an already initialized object that can be changed to whatever you need now. And the GC doesn't have to move a lot of objects around in memory since fewer objects have "died".

    The string issue has no solutions ultimately.
    You can work with StringBuilder as much as possible. That's what TextMeshPro does, it is really effective that way since you don't need "actual strings".

    There's one overload like SetText(StringBuilder) which just copies out the characters in there to an internal representation. And it also has SetText(format, arg1, arg2,...) which has special handling. Why?
    Because
    string s = 5.3.ToString(); obviously cannot get a string out of nowhere, it has to be allocated, and once it is not used anymore then it becomes garbage that has to be cleaned up eventually. In my exmaple here it is immediately discarded as garbage after passing it to TextMeshPro!!

    That's why those two methods are so useful. In the first one you can assemble your own pseudo strings in a stringbuilder, and in the second one you can use a never-changing format string that gets values put into it through arguments (it's optimized so it does NOT do the float.ToString() thing of course).


    But your question was about the general case, like when you're not working with TextMeshPro, right?
    In that case there's no general solution.
    You could immitate what TMP does with your own StringBuilder stuff if that makes sense at that moment.
    But ultimately every "string += " or .ToString() will always allocate many string fragments. And StringBuilder is one of the possible ways to avoid that (and there are many others)
     
  13. Shayke

    Shayke

    Joined:
    Dec 8, 2017
    Posts:
    352
    I guess i'll start using textmeshpro.
    Thanks for all the details! :)
     
  14. Shayke

    Shayke

    Joined:
    Dec 8, 2017
    Posts:
    352
    I have been thinking that i could use this method to reallocate my memory:
    System.GC.Collect();

    But it seems like it has no effect.
    Why?