Haha, yeah I noticed that too.
No solution yet, unfortunately.
This problem appeared in the Unity Bar&Grill Skype chat so I thought I’d take the time to post my solution.
The profiler reported that MonoBehaviour.OnMouse_ produced 0.6KB of garbage per frame, which is simply not acceptable when developing for smartphone and other similar devices. After some research I concluded that there was no supported way of disabling this event. So I took a peek at the source and produced the following piece of code.
Slap it on a gameobject and make sure the script is high in ExecutionOrder.
using UnityEngine;
using System.Reflection;
using System;
// This script should be first in Script Execution Order
// This script lobotomizes Unity's OnMouse events to remove the related garbage generation
public class MouseEventSupressor : MonoBehaviour
{
private Action SetMouseMoved;
void Start()
{
// Locate the internal class SendMouseEvents
Assembly assembly = typeof(MonoBehaviour).Assembly;
Type type = assembly.GetType("UnityEngine.SendMouseEvents");
// Create an Action of the method SetMouseMoved which sets the flag s_MouseUsed
MethodInfo method = type.GetMethod("SetMouseMoved",
BindingFlags.Static | BindingFlags.NonPublic);
SetMouseMoved = (Action)Delegate.CreateDelegate(typeof(Action), method);
SetMouseMoved();
// Set the length of the m_CurrentHit array to zero, stops the SendEvents calls
FieldInfo info = type.GetField("m_CurrentHit",
BindingFlags.NonPublic | BindingFlags.Static);
info.SetValue(null, Array.CreateInstance(info.FieldType.GetElementType(), 0));
}
void Update ()
{
// Call the SetMouseMoved function at the start of every Update
// This stops a variety of raycasting and get component calls which create garbage
SetMouseMoved();
}
}
What version of Unity are you running. I’m in 5.1.4f1 and ‘method’ is null.
I’m on 5.2.3f1. The relevant class has most likely been refactored since 5.1.4f1 - one of the dangers of reflection.
Don’t suppose you know one that works with 5.1.4f1? I had a play with Public attributes, but I can’t find the relevant method
Thanks for sharing your solution. Now I need a little help how to use your script properly. After attaching it to gameobject, I have noticed that GC.Collect started to execute periodically.
Alright, I just banged my head for an hour now and ended up reading the source code.
-
The whole system is retarded. You have no way to stop Unity from calling that specific loop, since it’s called to a static method directly from the native side. You can only force it to do as little as possible. (Like the reflection solution from Fredrik)
-
“camera.eventMask = 0;” does indeed do something; it prevent that loop from performing raycast. So, you save your millisecond there… but not the garbage generated.
-
With 3 camera active, we were getting 1.2Kb of garbage every frame. Unity perform a GetComponent() on every camera. Since Unity 4.6, GetComponent is optimized to cache a previous search and not generate garbage every frame you invoke it. So, why does that specific call in that specific place generating so much crap? Simple, we had no GUILayer on our 2nd and 3rd camera. Unity - being again, a bit retarded - is unable to simply return “null” on a GetComponent. It’s returning a new UnityEngine.Object that return true when compared to null, but is NOT null. Every frame you do GetComponent on a GameObject which does not have that component, it generates garbage.
TL;DR: Do eventMask = 0 and make sure every single camera has a GUILayer. There, no more wasted ms and no more garbage.
Thanks for playing detective for the rest of us. Will test this.
@superpig , now that you are on the inside, and are a part of how the sausage is made, so to speak, any insights on this?
Reflecting into Unity internals to turn off messages that might be used somewhere else just doesn’t sound like a good idea.
The 1.2Kb of garbage on the GetComponent only happens in Editor. Profile your game in a Player, not the Editor.
Has this been fixed already? Even on our server scene (no camera, no gui) the garbage is generated.
I know about how unity create a string or something when getting a null off a GameObject, but honestly, Unity being unable to return a proper null is just plain stupid.
@LightStriker_1 There was a blog post about this about 2 years ago asking if they should change it, I’m assuming they never did.
And I highly doubt they ever will.
When the game is profiled as a build (not in Editor), some garbage will still be allocated from time to time due to this issue.
For the most part, the allocations won’t happen, but scrubbing down the Profiler shows there are still some allocations.
This is something that should really be fixed.
Setting the eventMask did not work for me.
What did work was making sure your main camera has the GUILayer component. The garbage seems to be created by internal mouse events constantly calling GetComponent().
This totally worked for me:
Since GuiLayer is slowly becoming depreciated I assume this issue will resolve itself as soon as this class disappears completely in one of future releases.
Thanks @ImpactBlue
This seems to still be an issue. I’m in 2017.4.3
Adding the GUILayer Component to the main camera solved the issue for me.
And in 2018.2 still exists LOL.
But hey, unity added a new transform tool that combines scale rotate and translate, that literally no one asked for. So they are kinda doing something.