Object lifetime, GC and the State Pattern [modified]
-
Hi everybody I'm currently experimenting with design patterns, one of them is the design pattern. First some code: This will init my application, it will init itself then by switching from state to state
static void Main(string[] args)
{
ScreenInitState startState = ScreenInitState.GetInstance();
Console.WriteLine("All states exited");Console.WriteLine("Press any key to exit."); Console.ReadKey();
}
Here we switch from state to state
abstract class InitState
{
protected void Switch(InitState state, bool bStopSelf)
{
if (bStopSelf)
Stop();
}abstract protected void Stop();
}
class ScreenInitState : InitState
{
private ScreenInitState()
{
// init screen here and go to next stateSwitch(InputInitState.GetInstance(), true); } // ...
}
class InputInitState : InitState
{
private InputInitState()
{
// init input here and go to next stateSwitch(SoundInitState.GetInstance(), true); } // ...
}
So the app starts like this: Main -> SreenInitState -> InputInitState -> SoundInitState -> ... Now when I'm in the last state, do all previous states still exist in memory or are the collected by the GC? Though this pattern is very useful I'm concerned about memory usage here. Does anyone know what happens to the objects during runtime? regards -- modified at 9:54 Tuesday 6th June, 2006
-
Hi everybody I'm currently experimenting with design patterns, one of them is the design pattern. First some code: This will init my application, it will init itself then by switching from state to state
static void Main(string[] args)
{
ScreenInitState startState = ScreenInitState.GetInstance();
Console.WriteLine("All states exited");Console.WriteLine("Press any key to exit."); Console.ReadKey();
}
Here we switch from state to state
abstract class InitState
{
protected void Switch(InitState state, bool bStopSelf)
{
if (bStopSelf)
Stop();
}abstract protected void Stop();
}
class ScreenInitState : InitState
{
private ScreenInitState()
{
// init screen here and go to next stateSwitch(InputInitState.GetInstance(), true); } // ...
}
class InputInitState : InitState
{
private InputInitState()
{
// init input here and go to next stateSwitch(SoundInitState.GetInstance(), true); } // ...
}
So the app starts like this: Main -> SreenInitState -> InputInitState -> SoundInitState -> ... Now when I'm in the last state, do all previous states still exist in memory or are the collected by the GC? Though this pattern is very useful I'm concerned about memory usage here. Does anyone know what happens to the objects during runtime? regards -- modified at 9:54 Tuesday 6th June, 2006
What's behind SoundInitState.GetInstance()? Every time I've written something with an Instance property or a GetInstance(), it's been a singleton. If all of your states are singletons, the GC isn't collecting them. Also, what does Stop() do in each of the states? You'd need to be designing something pretty complicated to warrant singleton states. In general, states work better as flyweights. I'd say use structs, but they break the inheritance model.
-
What's behind SoundInitState.GetInstance()? Every time I've written something with an Instance property or a GetInstance(), it's been a singleton. If all of your states are singletons, the GC isn't collecting them. Also, what does Stop() do in each of the states? You'd need to be designing something pretty complicated to warrant singleton states. In general, states work better as flyweights. I'd say use structs, but they break the inheritance model.
Stephan Samuel wrote:
What's behind SoundInitState.GetInstance()? Every time I've written something with an Instance property or a GetInstance(), it's been a singleton.
Correct, that's the case here
Stephan Samuel wrote:
Also, what does Stop() do in each of the states?
Just a function where the state will cleanup itself (remove resources etc) before switching to the next state
Stephan Samuel wrote:
the GC isn't collecting them
So you suggest to use some sort of structs + switch-calls to keep the memory footprint as small as possible? Or does it help to design my states as normal instances instead of singletons?
-
Hi everybody I'm currently experimenting with design patterns, one of them is the design pattern. First some code: This will init my application, it will init itself then by switching from state to state
static void Main(string[] args)
{
ScreenInitState startState = ScreenInitState.GetInstance();
Console.WriteLine("All states exited");Console.WriteLine("Press any key to exit."); Console.ReadKey();
}
Here we switch from state to state
abstract class InitState
{
protected void Switch(InitState state, bool bStopSelf)
{
if (bStopSelf)
Stop();
}abstract protected void Stop();
}
class ScreenInitState : InitState
{
private ScreenInitState()
{
// init screen here and go to next stateSwitch(InputInitState.GetInstance(), true); } // ...
}
class InputInitState : InitState
{
private InputInitState()
{
// init input here and go to next stateSwitch(SoundInitState.GetInstance(), true); } // ...
}
So the app starts like this: Main -> SreenInitState -> InputInitState -> SoundInitState -> ... Now when I'm in the last state, do all previous states still exist in memory or are the collected by the GC? Though this pattern is very useful I'm concerned about memory usage here. Does anyone know what happens to the objects during runtime? regards -- modified at 9:54 Tuesday 6th June, 2006
As you are switching from state to state by using a method in each object, the objects can't be garbage collected. The Switch method of each previous state is still executing until the last state is finished. When the last state returns from the Switch method, all previous Switch calls will finish in turn and release the objects. This is not a problem, however, as long as you make the Stop method release all objects contained in it's state object. --- b { font-weight: normal; }
-
As you are switching from state to state by using a method in each object, the objects can't be garbage collected. The Switch method of each previous state is still executing until the last state is finished. When the last state returns from the Switch method, all previous Switch calls will finish in turn and release the objects. This is not a problem, however, as long as you make the Stop method release all objects contained in it's state object. --- b { font-weight: normal; }
Guffa wrote:
This is not a problem, however, as long as you make the Stop method release all objects contained in it's state object.
That's what I do. So the only thing left in memory will be the instance of the state objects and nothing more? I hope this isn't too much overhead as a drawback for clean design.
-
Stephan Samuel wrote:
What's behind SoundInitState.GetInstance()? Every time I've written something with an Instance property or a GetInstance(), it's been a singleton.
Correct, that's the case here
Stephan Samuel wrote:
Also, what does Stop() do in each of the states?
Just a function where the state will cleanup itself (remove resources etc) before switching to the next state
Stephan Samuel wrote:
the GC isn't collecting them
So you suggest to use some sort of structs + switch-calls to keep the memory footprint as small as possible? Or does it help to design my states as normal instances instead of singletons?
You should keep your states small. Structs won't work because they don't implement inheritance, but try to keep the information inside your concrete state classes to a minimum. I would avoid the singleton pattern for states. Currently, your states don't really switch. Each tunnels through to the next. There should probably be one top-level controller (it may be a singleton but may not need to be) that decides which state you're in and runs the states: (Please pardon any typos or syntax errors; I'm making this up as I go.)
public class MyController { State currentState; public void RunMe() { while (this.currentState != null) this.currentState = this.currentState.RunMe(); } } public abstract class State { public abstract State RunMe(); } public class ConcreteState1() { public RunMe() { // do things. return new ConcreteState2(); } } public class ConcreteState2() { public RunMe() { // do things. return null; } }
Likely, you'll want to pass around some objects, and your states will pass out different "next state" objects as RunMe() returns based on what those objects look like. Each state lives only as long as it's executing, so there's no memory overhead. If you're worried about setup/tear-down performance of your state objects (e.g. -- if they have a complicated DB open process and you need them to run really quickly with persistent connections), consider some level of factory for the states: either have a connection factory, give each state its own factory and let it decide when to create a new one of itself, or create a factory class (or implement one in MyController) that decides the lifetime of your state objects. I'd also implement IDisposable and the C# disposal pattern for each of your state objects to clear up unmanaged resources. Managed resources should get cleaned up automatically. The other way to implement this is to have MyController decide which state is next based on the state of some object. My personal belief is that method isn't as good. It's less OO: you might as well just code all the possibilities within the controller and forget the states. -
You should keep your states small. Structs won't work because they don't implement inheritance, but try to keep the information inside your concrete state classes to a minimum. I would avoid the singleton pattern for states. Currently, your states don't really switch. Each tunnels through to the next. There should probably be one top-level controller (it may be a singleton but may not need to be) that decides which state you're in and runs the states: (Please pardon any typos or syntax errors; I'm making this up as I go.)
public class MyController { State currentState; public void RunMe() { while (this.currentState != null) this.currentState = this.currentState.RunMe(); } } public abstract class State { public abstract State RunMe(); } public class ConcreteState1() { public RunMe() { // do things. return new ConcreteState2(); } } public class ConcreteState2() { public RunMe() { // do things. return null; } }
Likely, you'll want to pass around some objects, and your states will pass out different "next state" objects as RunMe() returns based on what those objects look like. Each state lives only as long as it's executing, so there's no memory overhead. If you're worried about setup/tear-down performance of your state objects (e.g. -- if they have a complicated DB open process and you need them to run really quickly with persistent connections), consider some level of factory for the states: either have a connection factory, give each state its own factory and let it decide when to create a new one of itself, or create a factory class (or implement one in MyController) that decides the lifetime of your state objects. I'd also implement IDisposable and the C# disposal pattern for each of your state objects to clear up unmanaged resources. Managed resources should get cleaned up automatically. The other way to implement this is to have MyController decide which state is next based on the state of some object. My personal belief is that method isn't as good. It's less OO: you might as well just code all the possibilities within the controller and forget the states.Great. The Controller object really makes sense and keeps memory overhead at a minimum, that's a really good way, I like. The only addition I will make is to keep a
Stack<State>
in my controller, so that some states will still be able to overlap each other, like a menu on top of a game. Thanks a bunch! :) -
Guffa wrote:
This is not a problem, however, as long as you make the Stop method release all objects contained in it's state object.
That's what I do. So the only thing left in memory will be the instance of the state objects and nothing more? I hope this isn't too much overhead as a drawback for clean design.
Greeeg wrote:
So the only thing left in memory will be the instance of the state objects and nothing more?
If you get rid of all references in the object (setting them to null), all objects that it used are up for garbage collection. If the memory is needed, they will be collected. --- b { font-weight: normal; }