- Home /
GC collects variable that is still in use
I have a small class to output debug output in the GUI:
using UnityEngine;
using System.Collections;
public class GUIConsole : MonoBehaviour
{
public int numLines = 10;
private string message;
private Queue queue;
// Use this for initialization
void Start ()
{
Application.RegisterLogCallback(OnLog);
queue = new Queue();
}
// Update is called once per frame
void Update ()
{
}
void OnGUI ()
{
foreach ( string line in queue )
GUILayout.Label (line);
while ( queue.Count > numLines ) queue.Dequeue();
}
void OnLog (string message, string callStack, LogType type)
{
//this.message += message + "\n";
queue.Enqueue(message);
}
}
When I pause execution in Unity and resume it again, I get a null reference exception. Further investigation showed that my queue variable was suddenly null. Only after I added this line in start, it stopped:
System.GC.KeepAlive(queue);
Any idea why the GC collects my object?
[EDIT] So, some further investigation showed: It isn't just pausing & resuming. Pausing is enough. I don't need to resume. But it only happens when I pause it, modify code and tab back to unity which auto-recompiles. This auto-recompile seems to cause the problem. It then shows the error
NullReferenceException: Object reference not set to an instance of an object GUIConsole.OnGUI () at Assets/Scripts/GUIConsole.cs:26)
a few times and then of course spams it if I resume.
[EDIT] Adding the suggestions in the answer:
using UnityEngine;
using System;
using System.Collections;
[Serializable]
public class GUIConsole : MonoBehaviour
{
public int numLines = 10;
[SerializeField]
public Queue queue;
// Use this for initialization
void Start ()
{
Application.RegisterLogCallback(OnLog);
queue = new Queue();
}
void OnGUI ()
{
foreach ( string line in queue )
GUILayout.Label (line);
while ( queue.Count > numLines ) queue.Dequeue();
}
void OnLog (string message, string callStack, LogType type)
{
queue.Enqueue(message);
}
}
Hower this didn't help with the problem. It is still happening
I wasn't able to replicate the behavior. $$anonymous$$y queue remains alive even without explicitly telling the GC to keep it alive.
I added a Debug.Log in (the empty) Update to get stuff in the Queue. Then I added this script to a GameObject, pressed play, then pause, and pause again. No null reference error.
Out of curiosity, is your Queue class set as System.Serializable. The problem may arise from the fact that Unity serializes and deserializes so often.
TrickyHandz: I don't know how I can check that. The code you see is the whole file, I am not doing anything else with the Queue class anywhere else.
Jamora: I updated the scenario
Answer by Jamora · Oct 13, 2013 at 07:57 PM
Unity performs a serialize/deserialize cycle every time you press the Play button or recompile a script. Any reference not marked as serializable will be lost there.
The way you can (try to) keep the reference is by either making it a public field, or marking that field with the [[SerializeField]][1] attribute. Then the Unity Serializer knows to attempt to restore that after an assembly reload. Only classes that have the System.Serializable attribute can be attempted to be serialized. While System.Collections.Queue has that attribute, it is not supported by the Unity serializer.
The unity serializer can serialize
All classed inheriting from UnityEngine.Object, for example Gameobject, Commponent, MonoBehaviour, Texture2D, AnimationClip.. - All basic data types like int, string, float, bool. - Some built in types like Vector2, Vector3, Vector4, Quaternion, Matrix4x4, Color, Rect, Layermask.. - Arrays of a serializable type
List of a serializable type (new in Unity2.6)
Enums
Read more about Unity Serialization in the Unity Technologies Blog
You will have to implement your queue as a System.Collections.Generic.List. You will also need to rename your current Start method into OnEnable, because Start is only called once, so your log callback won't work after an assembly reload.
[1]: http://docs.unity3d.com/Documentation/ScriptReference/SerializeField.html
Your answer explains pretty good what is probably happening, however, adding [Serializeable] and [SerializeField] didn't fix the problem. I added the new code to the post
Updated my answer. Turns out Queue isn't supported by the Unity serializer.
Your answer
Follow this Question
Related Questions
Distribute terrain in zones 3 Answers
Multiple Cars not working 1 Answer
how to send data from client to client? 1 Answer
C# Error help ( error CS0023 The `!’ operator cannot be applied to operand of type `string’ ) ??? 1 Answer
An OS design issue: File types associated with their appropriate programs 1 Answer