Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by Forc3ment · Jul 03, 2018 at 08:00 AM · materialsmemory-leak

Changing materials cause memory leaks

Hi everyone,

I have problem of memory leak when using materials. I read some thread about this but I didn't found the answer i was looking for. So I need to change all the materials on a gameobject each second and the materials I need are kept in an array. The problem is that some copies of the materials are kept in memory every time I change the materials.

Here is the code I use:

 foreach (GameObject g in Rooms)
 {
       if (g != null)
       {
             int index = a number computed;
             Material[] mats = g.GetComponent<MeshRenderer>().materials;
             for (int j = 0; j < g.GetComponent<MeshRenderer>().materials.Length; j++)
             {
                  mats[j] = StoredMaterial[index];
             }
             g.GetComponent<MeshRenderer>().materials = mats;
       }
 }

I tried to found a work around but I found none that resolve all my problem. If i use the following code, I do note have the leaks anymore but only the first material is changed and if the gameobjects have more than one materials it did not work well.

  foreach (GameObject g in Rooms)
  {
        if (g != null)
        {
              int index = a number previously computed;
              g.GetComponent<MeshRenderer>().material = StoredMaterial[index];
        }
  }

StoredMaterial is an Array of Materials where are stored the different materials that could be used at every iteration of my application to colorize the differents gameobjects with the good color. And the goal is to change the color of some part of a big object at runtime using external data to pick the correct color in the StoredMaterial array. And as I build on a low performance device I must take care of the perf of my application.

Thanks in advance for your help.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

4 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by Forc3ment · Jul 09, 2018 at 01:55 PM

It appears that the garbage collector do not collect unused materials and as I do not destroy the materials I replace, it creates a memory leaks. I just had to destroy the Materials in g.GetComponent().materials before assigning them again. In order to change all the materials on one gameobject without creating a leak, I first create a array with the good size, then for each materials inside, I destroy the current one and add the new one in the array. Then replace the old array with the new one.

         Material[] mats = new Material[g.GetComponent<MeshRenderer>().materials.Length];
         for (int j = 0; j < g.GetComponent<MeshRenderer>().materials.Length; j++)
         {
             Destroy(g.GetComponent<MeshRenderer>().materials[j]);
             mats[j] = StoredMaterial[index];
         }
         g.GetComponent<MeshRenderer>().materials = mats;
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
8

Answer by Bunny83 · Jan 07, 2020 at 08:07 PM

Since all answers are either wrong or provide bad (almost horrible) solutions I'll post an answer.


Many people seem to not understand or are not aware of the difference between the material / materials property compared to the sharedMaterial / sharedMaterials property. Whenever you use the material or materials property (use means either reading or writing it) Unity will automatically instantiate the material for this renderer unless it already has its own instance. This has many severe consequences.


First of all as observed the instantiated materials are not automatically destroyed when you replace the material. This is actually true for all objects that are derived from UnityEngine.Object. So this holds true for Mesh, Material, GameObject, Component, ScriptableObject, .. For GameObjects and its components there's a slight difference. When destroying a gameobject all components and sub gameobjects are destroyed as well. However destroying a gameobject or the renderer component does not destroy an instantiated Material or Mesh. The material is not "owned" by the renderer and could potentially be used by other objects as well. This is not possible with components.


Besides the duty of cleaning up the instantiated Materials when using those properties is that instantiated materials are seperate materials. That means they will always cause to be rendered with its own drawcall, even when all parameters are the same. So looping through 10 objects and assigning the same material to the material / materials property will actually create 10 seperate materials. Such materials will not be batched. So by using those properties you essentially loose any batching support for those objects.


The properties sharedMaterial and sharedMaterials on the other hand do not automatically instantiate the Material. That means if you have 10 objects and you assigned the same material to all 10 sharedMaterial properties, they will all use the same material. Such objects can actually be batched (statically or dynamically). Of course that also means you can not change any material attributes only for one object. So when changing the shared material all objects that are using that material will be affected.


Unfortunately at the moment we can not check / test if a renderer actually has an instantiated material or not because any access to material / materials would immediately instantiate the material(s). So like mentioned in the documentation of the material property you are responsible for keeping track of where you actually created instances of Materials.


About the code snippet in the question another warning when using the materials or sharedMaterials property. They return an array of materials. However each time you read this property a new array will be created. Since the for loop uses .materials.Length in the loop condition the code would create a new array for every loop iteration. Of course those arrays will be garbage collected but it's unnecessary created garbage. The code in the OP's answer is even worse. Instead of using materials and causing an instantiation of all those materials he should just use sharedMaterials without destroying anything. So the proper answer would be:

 MeshRenderer rend = g.GetComponent<MeshRenderer>();
 Material[] mats = rend.sharedMaterials;
 for (int j = 0; j < mats.Length; j++)
 {
     mats[j] = StoredMaterial[index];
 }
 rend.sharedMaterials = mats;

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image uatarONE · Aug 04, 2020 at 07:49 AM 0
Share

This should (also) be the correct answer for the asked question. Cool explanation. Please don't stop answering questions in this matter. Even if the info is just a little too much for the intended purpose, I enjoyed the read and it gave me everything to understand how it works (as much as we can).

avatar image
1

Answer by im012 · Jul 09, 2018 at 01:13 PM

You Should Use System.Gc.Collect for this .

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Forc3ment · Jul 09, 2018 at 01:58 PM 0
Share

I think it should work but this operation is I think to heavy for my device to be done at each update.

avatar image Ultroman · Jan 07, 2020 at 04:00 PM 0
Share

System.GC.Collect does NOT collect unreferenced ASSETS. Only Resources.UnloadUnusedAssets() does that, and it also calls System.GC.Collect internally. Also, both of these are potentially heavy function-calls, which should not be used lightly. At least, I don't think it should warrant a GC or any such operation to remove a material from memory.

avatar image
0

Answer by madks13 · Jul 03, 2018 at 08:59 AM

Can you give more details on what you're trying to achieve here? Someone might give you another way of doing it. Also, what is StoredMaterial?

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Forc3ment · Jul 03, 2018 at 02:41 PM 0
Share

I edited the post.

avatar image madks13 Forc3ment · Jul 04, 2018 at 03:13 PM 0
Share

If i understood correctly, you are changing object colors based on external data, with update tick of 1s or less? Do you need to update even if the color stays the same?

avatar image Forc3ment madks13 · Jul 09, 2018 at 12:05 PM 0
Share

I may verify if the materials need to be changed but the problem will remains with those wich need to be changed.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

97 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Changing the material in an array of materials at run time 2 Answers

How to replace materials in the materials array 3 Answers

Collada import material Main Colors 0 Answers

Is there a way to export animated UVs from a 3d package? 2 Answers

Any suggestions on this approach to multiple objects and materials 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges