In this Flambe guide it says:
"This dispose function removes this component from its owning entity. You should override the dispose-function in order to dispose objects yourself, to prevent memory leaks."
I have 3 questions:
How should I override the dispose function?
How to properly use the dispose function?
Is there a way to check for memory leaks in Flambe?
1 If you're using Component
override public function dispose() {
myReferences = null;
myDisposable.dispose();
super.dispose();
}
If you are not using a Component:
You can implement Disposable and dispose when needed in another dispose function.
2 You need to clear references to objects, that means set it to null.
You need to close signal connections that are created in that context.
You need to dispose the Disposables.
3 If you use the JavaScript (html) target, you can use the chrome debug inspector / devtools. You can collect memory profiles, observe the cpu usage etc. Really useful! https://developer.chrome.com/devtools/docs/profiles
Related
I have made two different posts the last couple of days about we going from XNA to MonoGame and how the application increase in memory and no input from keyboard is detected after the first time it has been launched.
Using WinForms with a button to start a MonoGame.
private void button1_Click(object sender, EventArgs e)
{
viThread = new Thread(Demo);
viThread.Priority = ThreadPriority.Highest;
viThread.Start();
}
private void Demo()
{
using(Demo d = new Demo())
d.Run();
}
Since Monogame are using SharpDX (XNA did not) I call for a function when i Exit the application with Game.Exit() which look like:
SharpDX.Diagnostics.ObjectTracker.ReportActiveObjects().Length;
The number is always above 600. How can I Dispose/Remove all resources? I think that will solve both problems (memory leak for sure). Greetings
Both MonoGame and your code should dispose all objects and it will ultimately dispose SharpDX resources, but you should not having to dispose SharpDX resources directly. As MonoGame is a facade to SharpDX, it is usually considered as the owner of SharpDX objects. I don't know the details about MonoGame implementation, so I don't know if they are handling the whole Dispose process correctly but you should check this with them (A dispose of a Game class should call dispose on all GameComponent including the ContentManager... etc.)
I might be on the wrong track here, but here goes:
In my PhoneGap Durandal app, I have a Profile View/VM which only returns data the first time it is hit - after that it checks a bool called initialised and wont hit the DB again the 2nd time. This works fine.
However after Logout, I need to invalidate the cache. I could use a message to tell the Profile VM to clear the variable (ie. invalidate the cache) but I thought perhaps there is a higher-level way of doing this in Durandal - e.g. On Logout, I tell dispose of all ViewModels in memory (there may be other Singleton objects with session specific info in them).
Advice please...
This is more of a javascript question and this is just my understanding of how javascript works.
Javascript will automatically dispose of objects that are no longer referenced through a mechanism called Garbage Collection.
Here is a good article on how Garbage Collection works. Basically it will dispose of objects that are no longer referenced in your program.
There is another method in javascript that allows you to remove objects. The delete method:
delete someobj;
Which too my knowledge is pretty much equal to someobj = undefined;
Hope this helps.
***Edit
Durandal follows the screen activator pattern for it's viewmodels. So apart of the viewmodel lifecycle it will call an activate, candeactivate, and deactivate method.
You could do your disposing in the deactivate method.
(Durandal 2.0) You could always hook into the composition life-cycle callback methods on your view-model. There are four: activate(), attached(), deactivate(), and detached(). They are called automatically by Durandal on your view-model, if they exist. In my projects, if I need a view to invalidate its cache, I hook into the deactivate() method and put the cleanup logic there. Similarly, I use the detached() method to unbind events and destroy UI widgets.
Simple example:
define(['modules/myDataService'],
function(dataservice) {
var cache;
function activate() {
return dataservice.getData().done(function(response) {
cache = response;
});
}
function deactivate() {
cache = null;
}
return {
activate: activate,
deactivate: deactivate
};
});
Source documentation: http://durandaljs.com/documentation/Hooking-Lifecycle-Callbacks/
Note: I've created a simple project—you can see how switching types between UIButton and CustomButton in storyboard changes GC behavior.
I'm trying to get my head wrapped around MonoTouch garbage collector.
The issue is similar to the one fixed in MT 4.0, however with inherited types.
To illustrate it, consider two view controllers, parent and child.
Child's view contains a single UIButton that writes to console on tap.
Controller's Dispose method throws an exception so it's hard to miss.
Here goes child view controller:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
sayHiButton.TouchUpInside += (sender, e) =>
SayHi();
}
}
void SayHi()
{
Console.WriteLine("Hi");
}
protected override void Dispose (bool disposing)
{
throw new Exception("Hey! I've just been collected.");
base.Dispose (disposing);
}
Parent view controller just presents child controller and sets a timer to dismiss it and run GC:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
var child = (ChildViewController)Storyboard.InstantiateViewController("ChildViewController");
NSTimer.CreateScheduledTimer(2, () => {
DismissViewController(false, null);
GC.Collect();
});
PresentViewController(child, false, null);
}
If you run this code, it predictably crashes inside ChildViewController.Dispose() called from its finalizer because child controller has been garbage collected. Cool.
Now open the storyboard and change button type to CustomButton. MonoDevelop will generate a simple UIButton subclass:
[Register ("CustomButton")]
public partial class CustomButton : UIButton
{
public CoolButton (IntPtr handle) : base (handle)
{
}
void ReleaseDesignerOutlets()
{
}
}
Somehow changing the button type to CustomButton is enough to trick garbage collector into thinking child controller is not yet eligible for collection.
How is that so?
This is an unfortunate side-effect of MonoTouch (who is garbage collected) having to live in a reference counted world (ObjectiveC).
There are a few pieces of information required to be able to understand what's going on:
For every managed object (derived from NSObject), there is a corresponding native object.
For custom managed classes (derived from framework classes such as UIButton or UIView), the managed object must stay alive until the native object is freed [1]. The way it works is that when a native object has a reference count of 1, we do not prevent the managed instance from getting garbage collected. As soon as the reference count increases above 1, we prevent the managed instance from getting garbage collected.
What happens in your case is a cycle, which crosses the MonoTouch/ObjectiveC bridge and due to the above rules, the GC can't determine that the cycle can be collected.
This is what happens:
Your ChildViewController has a sayHiButton. The native ChildViewController will retain this button, so its reference count will be 2 (one reference held by the managed CustomButton instance + one reference held by the native ChildViewController).
The TouchUpInside event handler has a reference to the ChildViewController instance.
Now you see that the CustomButton instance will not be freed, because its reference count is 2. And the ChildViewController instance will not be freed because the CustomButton's event handler has a reference to it.
There are a couple of ways to break the cycle to fix this:
Detach the event handler when you no longer need it.
Dispose the ChildViewController when you no longer need it.
[1] This is because a managed object may contain user state. For managed objects which are mirroring a corresponding native object (such as the managed UIView instance) MonoTouch knows that the instance can not contain any state, so as soon as no managed code has a reference to the managed instance, the GC can collect it. If a managed instance is required at a later stage, we just create a new one.
I think I'm getting close to understanding how Mono GC and ObjC ref counting live together.
The way it works is that when a native object has a reference count of 1, we do not prevent the managed instance from getting garbage collected. As soon as the reference count increases above 1, we prevent the managed instance from getting garbage collected.
This is because a managed object may contain user state. For managed objects which are mirroring a corresponding native object (such as the managed UIView instance) MonoTouch knows that the instance can not contain any state, so as soon as no managed code has a reference to the managed instance, the GC can collect it. If a managed instance is required at a later stage, we just create a new one.
So if I create a CustomButton that inherits UIButton, add it as subview to my View, let the managed reference slip out of scope and then run GC, this managed CustomButton still won't be eligible for collection.
Why can't it be collected? Of course it may have managed state like properties, but if there is no link to it from managed objects, who cares about this state? It may as well just disappear, why can't it?
I'm thinking of one possible reason: subscribing to CustomButton events won't keep it alive for the GC so when the object gets collected, events stop firing. This would perhaps result in unexpected behavior.
Is this correct? Are there other reasons for keeping the managed object alive even if no one links it?
Why can't it be collected? Of course it may have managed state like properties, but if there is no link to it from managed objects, who cares about this state? It may as well just disappear, why can't it?
Native code might have references to the object, which may cause the object to resurface to managed code again later.
I believe a code sample would illustrate what would happen:
class MyView : UIView {
public string ImportantSecret;
}
class AppDelegate : UIApplicationDelegate {
UIViewController vc;
public override bool FinishedLaunching (UIApplication app,
NSDictionary options)
{
var myView = new MyView ();
myView.ImportantSecret = "MonoTouchRocks";
vc = new UIViewController ();
vc.View = new UIView ();
vc.View.AddSubView (myView);
// When this method returns the only place where myView is referenced
// is from inside the *native* Subviews collection.
BeginInvokeOnMainThread (() =>
{
Console.WriteLine (((MyView) vc.Subviews [0]).ImportantSecret);
// If the MyView instance was garbage collected and recreated
// automatically at this point, ImportantSecret would be null.
});
}
}
Important: this code is just to illustrate the reason why the GC can't collect managed objects which may have state. This particular sample would actually not forget the important secret, since the Subviews array is automatically cached in managed code - but this is not generally true.
I'm having issues with my Application Object. I am currently using a Service to simulate incoming data from an electronic game board. This data is represented as a 2D boolean array. Every five seconds the Service uses a method of the Application Object to update the array (setDetectionMap()). This array is being read by a Thread in my main Activity using another method (getDetectionMap()). After some debugging I am almost positive that the main Activity is not seeing the changes. Here is the code for my Application Object:
public class ChessApplication extends Application{
private static ChessApplication singleton;
private boolean[][] detectionMap;
public static ChessApplication getInstance(){
return singleton;
}
#Override
public void onCreate() {
super.onCreate();
singleton=this;
detectionMap=new boolean[8][8];
}
public boolean[][] getDetectionMap(){
return detectionMap;
}
public void setDetectionMap(boolean[][] newMap){
detectionMap=newMap;
Log.d("Chess Application","Board Changed");
}
}
I've checked my Manifest, I've rewritten my object declaration a dozen times, I've added LogCat tags to make sure that the code is executing when I think it should be, and I've even implemented the supposedly redundant Singleton code. Any ideas what could be causing this? Incidentally can anyone tell me how to view variable states as the activity is running? Thanks in advance.
Is your Activity calling getDetectionMap() to get the new map after the update occurs?
Because otherwise, it's holding onto a reference to the old boolean[][] array, wheras setDetectionMap(...) isn't actually updating the current data structure, it's just updating the "detectionMap" variable to point to a different one. As such, your main activity won't be aware of the swapout until the next time it calls getDetectionMap.
Easy fix: in setDetectionMap, manually copy values from newMap into detectionMap. Or, update the Activity's reference so it's looking at the right map.
One other observation entirely unrelated to the original question: It's quite unusual to override Application during Android development, and is usually considered a "code smell" unless you have a really good reason for doing so. In this case I imagine it's so that you can communicate between your service and Activity, but you create a middle-man where one isn't entirely necessary. Here's a useful SO thread on how to communicate directly between the two :)