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 + "

";
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

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] 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< string >. 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.