SFML community forums

Bindings - other languages => DotNet => Topic started by: myl on July 16, 2013, 11:39:50 am

Title: System.AccessViolation
Post by: myl on July 16, 2013, 11:39:50 am
After creating a RenderWindow and rendering lots of pretty things, i randomly had this piece of code throwing AccessViolations from the Text constructor.

public int GetTextWidthPixels(string text, Font font, uint fontSize)
{
       var textShape = new Text(text, font, fontSize);
       var bounds = textShape.FindCharacterPos((uint)(text.Length));
       textShape.Dispose();
       return (int)bounds.X;
}

The font is a static loaded resource, but to make sure, I've tested that the constructor doesn't misbehave if I pass null or a disposed Font, so this is not the issue.

I'm wondering if you could share any insight into the things that could be causing this behavior, so i know what to look for.
Title: Re: System.AccessViolation
Post by: Laurent on July 16, 2013, 11:43:17 am
Don't you have more detailed information about the exception? Like the call stack, or a human-friendly message?
Title: Re: System.AccessViolation
Post by: myl on July 16, 2013, 11:48:27 am
Well, the nature of AccessViolation is not very informative, which is why I'm asking :)

This is the top of the stack:
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
  at SFML.Graphics.Text.sfText_create()
  at SFML.Graphics.Text..ctor(String str, Font font, UInt32 characterSize)
Title: Re: System.AccessViolation
Post by: Laurent on July 16, 2013, 11:58:21 am
Make sure that the CSFML DLLs match your version of SFML.Net (do you have several version, or did you update an older version of SFML.Net?).
Title: Re: System.AccessViolation
Post by: myl on July 16, 2013, 12:07:08 pm
I've just verified that my dlls are the ones that go together out of the 32 bit .Net binary package.

FYI: Don't know if it helps, but I also experienced AccessViolations from the sprite copy constructor. I didn't mention this before because I haven't ruled out that i could be passing disposed sprites yet (which would also cause an AccessViolation).
Title: Re: System.AccessViolation
Post by: Laurent on July 16, 2013, 12:52:17 pm
Is it only these two calls that fail, or does any call to a sfml-graphics function result in the same thing?
Title: Re: System.AccessViolation
Post by: myl on July 17, 2013, 12:02:47 pm
I also have reports for
 
at SFML.Graphics.Sprite.sfRenderWindow_drawSprite(IntPtr CPointer, IntPtr Sprite, MarshalData& states)
at SFML.Graphics.Sprite.Draw(RenderTarget target, RenderStates states)
 
and also at
 
at SFML.Graphics.Text.sfRenderWindow_drawText(IntPtr CPointer, IntPtr Text, MarshalData& states)
at SFML.Graphics.Text.Draw(RenderTarget target, RenderStates states)
 
and at
 
at SFML.Graphics.Shape.sfShape_create(GetPointCountCallbackType getPointCount, GetPointCallbackType getPoint, IntPtr userData)
at SFML.Graphics.Shape..ctor()
 
So, pretty much all around. It usually occurs after a few hours of rendering. Profiling doesn't show any mem leaks.
Title: Re: System.AccessViolation
Post by: Laurent on July 17, 2013, 02:23:05 pm
Quote
It usually occurs after a few hours of rendering
Ah. So these functions work, but after a few hours the binding somehow gets unstable, right?
Title: Re: System.AccessViolation
Post by: myl on July 19, 2013, 01:29:52 am
Correctly understood.
Title: Re: System.AccessViolation
Post by: Laurent on July 19, 2013, 07:57:16 am
Probably a memory issue. Does the memory usage of your app increase over time?
Title: Re: System.AccessViolation
Post by: myl on July 19, 2013, 10:12:27 am
Which is what i guessed as well, but the leakeage is minor, if any, after profiling with ants.
Title: Re: System.AccessViolation
Post by: Laurent on July 19, 2013, 10:34:17 am
Since SFML.Net invokes CSFML dynamically, the profiler might not see everything that happens there.
Title: Re: System.AccessViolation
Post by: myl on July 21, 2013, 11:43:42 pm
Hey Laurent.
I can't seem to find any information on sfml memory management in .Net, so I'm wondering how I am supposed to go about this. At first I assumed it was handled for me. But since the Texture destructor makes a Destroy(false) call, this causes a leak. I guess it does this because you don't want to release resources on the GC thread. Is it right to conclude I MUST call Texture.Dispose() on my main thread before loosing the Texture reference to avoid any leaks?
Thanks!
Title: Re: System.AccessViolation
Post by: Laurent on July 22, 2013, 08:04:20 am
No it's wrong ;)

SFML resources are always destroyed (look at what Destroy(false) does). When it's done in the GC thread I just instanciate an OpenGL context because there's none.
Title: Re: System.AccessViolation
Post by: myl on July 22, 2013, 08:46:58 am
Glad I asked then :) This minimal example is leaking full on. What am I misunderstanding?
var renderWindow = new RenderWindow(new SFML.Window.VideoMode(200, 200), "I'm a leaker");
while (true)
{
    var texture = new Texture("nonprogressive.jpg");
    var sprite = new Sprite(texture);
    renderWindow.Draw(sprite);
    renderWindow.Display();
    renderWindow.DispatchEvents();
    GC.Collect();
}
 
Title: Re: System.AccessViolation
Post by: Laurent on July 22, 2013, 09:35:46 am
It looks like it should work fine ;D

I'll try to test it; how do you check that it leaks? With the Windows task manager or with a dedicated tool?
Title: Re: System.AccessViolation
Post by: myl on July 22, 2013, 10:00:34 am
It looks like it should work fine ;D
Great. Then we're on the same page.
I'll try to test it; how do you check that it leaks? With the Windows task manager or with a dedicated tool?
I use ANTS memory profiler, but leak is also obvious from task manager.
Title: Re: System.AccessViolation
Post by: myl on July 22, 2013, 10:09:42 am
Correction: It seems the mem "leak" that the task manager shows is eventually garbage collected. ANTS shows a private bytes leak that goes up to 1024mb (see screenshot) and after this point, the renderwindow turns white.
Title: Re: System.AccessViolation
Post by: myl on July 22, 2013, 10:16:15 am
FYI: The unit of the horizontal axis is minutes.

Another FYI: Inserting a texture.Dispose(); after drawing the sprite removes the leakage, but you say this shouldn't be necessary.
Title: Re: System.AccessViolation
Post by: Laurent on July 22, 2013, 10:22:41 am
Ok, thanks for the additional information.
Title: Re: System.AccessViolation
Post by: shawnliu on July 22, 2013, 10:48:38 pm
Hi, I will be glad to give you the answer. I am the author of xInterop NGen++ at http://www.xInterop.com (http://www.xInterop.com), which is a C# wrapper generator for native C++ DLL. I recently wrapped SFML libraries for testing purpose. I had a similar issue with my version of SFML C# Wrapper generated by xInterop NGen++ at http://www.xinterop.com/index.php/2013/07/20/generating-sfml-c-net-wrapper-libraries-in-10-minutes-part-i/ (http://www.xinterop.com/index.php/2013/07/20/generating-sfml-c-net-wrapper-libraries-in-10-minutes-part-i/).

The cause of the issue is GC management. When you call into any C++ native DLL, you must make sure any C# instantiated object you pass to the native C++ method will not get GC-collected during the call.

The solution is to use GC.KeepAlive or using keyword(your choice) to make sure that. So, your code should like the following,

var renderWindow = new RenderWindow(new SFML.Window.VideoMode(200, 200), "I'm a leaker");
while (true)
{
    var texture = new Texture("nonprogressive.jpg");
    var sprite = new Sprite(texture);
    renderWindow.Draw(sprite);
    renderWindow.Display();
    renderWindow.DispatchEvents();
    GC.KeepAlive(texture);
    GC.KeepAlive(sprite);
    GC.Collect();
}
GC.KeepAlive(renderWindow);
 

--------------------------------------------------------------------------------
Shawn Liu, Author of xInterop NGen++ at http://www.xInterop.com (http://www.xInterop.com).


Glad I asked then :) This minimal example is leaking full on. What am I misunderstanding?
var renderWindow = new RenderWindow(new SFML.Window.VideoMode(200, 200), "I'm a leaker");
while (true)
{
    var texture = new Texture("nonprogressive.jpg");
    var sprite = new Sprite(texture);
    renderWindow.Draw(sprite);
    renderWindow.Display();
    renderWindow.DispatchEvents();
    GC.Collect();
}
 
Title: Re: System.AccessViolation
Post by: Laurent on July 22, 2013, 10:59:40 pm
Thanks for your feedback.

The texture is correctly referenced in the sprite instance, and the sprite is used in the Draw call. In this scenario, I don't see how (when) the GC would collect one of these variables too early. When they are no longer referenced, they are not needed anymore.

And wouldn't that cause crashes rather than memory leaks?
Title: Re: System.AccessViolation
Post by: shawnliu on July 22, 2013, 11:19:52 pm
Being referenced in the scope does not mean much when the GC is running release mode when GC can be very aggressive. GC claim on the object could be as much as early you could think.

He did say he got AccessViolation exception if I recalled correctly.

Thanks for your feedback.

The texture is correctly referenced in the sprite instance, and the sprite is used in the Draw call. In this scenario, I don't see how (when) the GC would collect one of these variables too early. When they are no longer referenced, they are not needed anymore.

And wouldn't that cause crashes rather than memory leaks?
Title: Re: System.AccessViolation
Post by: shawnliu on July 22, 2013, 11:35:25 pm
You can also use Dispose method after you are done with the object if it supports IDisposable interface.

Hi, I will be glad to give you the answer. I am the author of xInterop NGen++ at http://www.xInterop.com (http://www.xInterop.com), which is a C# wrapper generator for native C++ DLL. I recently wrapped SFML libraries for testing purpose. I had a similar issue with my version of SFML C# Wrapper generated by xInterop NGen++ at http://www.xinterop.com/index.php/2013/07/20/generating-sfml-c-net-wrapper-libraries-in-10-minutes-part-i/ (http://www.xinterop.com/index.php/2013/07/20/generating-sfml-c-net-wrapper-libraries-in-10-minutes-part-i/).

The cause of the issue is GC management. When you call into any C++ native DLL, you must make sure any C# instantiated object you pass to the native C++ method will not get GC-collected during the call.

The solution is to use GC.KeepAlive or using keyword(your choice) to make sure that. So, your code should like the following,

var renderWindow = new RenderWindow(new SFML.Window.VideoMode(200, 200), "I'm a leaker");
while (true)
{
    var texture = new Texture("nonprogressive.jpg");
    var sprite = new Sprite(texture);
    renderWindow.Draw(sprite);
    renderWindow.Display();
    renderWindow.DispatchEvents();
    GC.KeepAlive(texture);
    GC.KeepAlive(sprite);
    GC.Collect();
}
GC.KeepAlive(renderWindow);
 

--------------------------------------------------------------------------------
Shawn Liu, Author of xInterop NGen++ at http://www.xInterop.com (http://www.xInterop.com).


Glad I asked then :) This minimal example is leaking full on. What am I misunderstanding?
var renderWindow = new RenderWindow(new SFML.Window.VideoMode(200, 200), "I'm a leaker");
while (true)
{
    var texture = new Texture("nonprogressive.jpg");
    var sprite = new Sprite(texture);
    renderWindow.Draw(sprite);
    renderWindow.Display();
    renderWindow.DispatchEvents();
    GC.Collect();
}
 
Title: Re: System.AccessViolation
Post by: myl on July 22, 2013, 11:42:02 pm
I can see why this thread has become a bit confusing, since maybe I should have created a new one when I started asking about memory management. The AccessViolations I experienced are unrelated to the minimal mem leak example. The AccessViolations in my own project didn't occur until I started to make attempts to eliminate leaks by overloading Texture Destructors and Calling Destroy(true) in them. It fixed the leak but caused AccessViolations.

So first things first. Let's try to fix the leak in the minimal code in a healthy way. Ideally without manually disposing textures or manually keeping them alive :)
Title: Re: System.AccessViolation
Post by: shawnliu on July 23, 2013, 12:07:18 am
If that is the case you should write code like the following I posted, as I said earlier, it will also prevent GC from reclaiming the objects earlier than you expect.

using(var renderWindow = new RenderWindow(new SFML.Window.VideoMode(200, 200), "I'm a leaker"))
{
    while (true)
   {
        using(var texture = new Texture("nonprogressive.jpg"))
        using(var sprite = new Sprite(texture))
       {
            renderWindow.Draw(sprite);
            renderWindow.Display();
            renderWindow.DispatchEvents();
       }
   }
}
 
Title: Re: System.AccessViolation
Post by: myl on July 23, 2013, 12:51:36 am
That is equivalent to running texture.Dispose() and sprite.Dispose() after drawing as discussed earlier, which solves the leak. But as I understand sfml intends these to be gc'ed properly by dereference.
Title: Re: System.AccessViolation
Post by: shawnliu on July 23, 2013, 02:50:30 am
The following is the original code you posted, it does not call Dispose method. Are you expecting the GC to release the texture and sprite object right after each loop with a call to GC.collect(). I don't think GC works that way as I know, I may be wrong though. Referencing and de-referencing object in GC is just a concept, I think its complication is way beyond that.

var renderWindow = new RenderWindow(new SFML.Window.VideoMode(200, 200), "I'm a leaker");
while (true)
{
    var texture = new Texture("nonprogressive.jpg");
    var sprite = new Sprite(texture);
    renderWindow.Draw(sprite);
    renderWindow.Display();
    renderWindow.DispatchEvents();
    GC.Collect();
}

Secondly, Developers are responsible for calling Dispose or using "using" keyword to call Dispose method. Otherwise, GC calls the finalizer to call Dispose if the pattern is implemented correctly.

If this is a memory issue, how much memory loss have you been seeing by running your code?

That is equivalent to running texture.Dispose() and sprite.Dispose() after drawing as discussed earlier, which solves the leak. But as I understand sfml intends these to be gc'ed properly by dereference.
Title: Re: System.AccessViolation
Post by: Laurent on July 23, 2013, 07:57:43 am
Quote
Being referenced in the scope does not mean much when the GC is running release mode when GC can be very aggressive. GC claim on the object could be as much as early you could think.
Ok, but... I don't think it can happen before the object is explicitly used in the function (i.e. before Draw(sprite)).
Title: Re: System.AccessViolation
Post by: shawnliu on July 23, 2013, 07:48:14 pm
I tested the same code by using "using keyword" for 1 hour using my own version of C# wrapper for SFML generated by NGen++, no memory leak, no crash. The underlying native C++ code is really robust, very stable.

I have not read the official version of C# wrapper code yet, I don't know the details, I can not comment.

If you use HandleRef in the class implementation, the object won't get reclaimed by GC during the P/Invoke call. So, you are right, it won't happen before the call, it can happen during the call if HandleRef or similar method is not used to prevent GC from reclaiming the object during the call.

Quote
Being referenced in the scope does not mean much when the GC is running release mode when GC can be very aggressive. GC claim on the object could be as much as early you could think.
Ok, but... I don't think it can happen before the object is explicitly used in the function (i.e. before Draw(sprite)).
Title: Re: System.AccessViolation
Post by: myl on July 24, 2013, 10:28:40 am
I tested the same code by using "using keyword" for 1 hour using my own version of C# wrapper for SFML generated by NGen++, no memory leak, no crash. The underlying native C++ code is really robust, very stable.

Nobody is arguing your way is not working. We are simply discussing whether SFML is working as it was intended by design (which it appears it is not quite).

Have you had a chance to confirm this Laurent? I'm just wondering whether I should start making workarounds or wait for a fix.
Title: Re: System.AccessViolation
Post by: Laurent on July 24, 2013, 11:18:52 am
No, I still didn't have to the time to test this, sorry.
Title: Re: System.AccessViolation
Post by: shawnliu on July 26, 2013, 12:19:56 am
I was trying to help. I am not arguing with you neither, I was simply presenting the fact.

I tested the same code by using "using keyword" for 1 hour using my own version of C# wrapper for SFML generated by NGen++, no memory leak, no crash. The underlying native C++ code is really robust, very stable.

Nobody is arguing your way is not working. We are simply discussing whether SFML is working as it was intended by design (which it appears it is not quite).

Have you had a chance to confirm this Laurent? I'm just wondering whether I should start making workarounds or wait for a fix.
Title: Re: System.AccessViolation
Post by: shawnliu on July 26, 2013, 12:27:28 am
And I will leave the topic and let you do you own work then.

I was trying to help. I am not arguing with you neither, I was simply presenting the fact.

I tested the same code by using "using keyword" for 1 hour using my own version of C# wrapper for SFML generated by NGen++, no memory leak, no crash. The underlying native C++ code is really robust, very stable.

Nobody is arguing your way is not working. We are simply discussing whether SFML is working as it was intended by design (which it appears it is not quite).

Have you had a chance to confirm this Laurent? I'm just wondering whether I should start making workarounds or wait for a fix.
Title: Re: System.AccessViolation
Post by: myl on July 29, 2013, 11:35:56 am
I was trying to help. I am not arguing with you neither, I was simply presenting the fact.

I think it's a simple misunderstanding of the meaning of the word "argue", which can be used in two ways; To give reasons or cite evidence in support of an idea (as was used here) or it can be used in an (often) angry manner to express opposing views. Nobody here is mad or angry :)

And any help here is welcome :)
Title: Re: System.AccessViolation
Post by: myl on August 28, 2013, 01:40:34 pm
Hey Laurent!

Any news on this leak issue? Does it have an issue #?

myl
Title: Re: System.AccessViolation
Post by: Laurent on August 28, 2013, 01:46:37 pm
No. I'm really sorry, I'm so busy with other tasks :(
Title: Re: System.AccessViolation
Post by: myl on January 08, 2014, 04:19:36 pm
Hey Laurent

I have some (hopefully) interesting inputs on this subject. I will be implementing and testing fixes and I'd be happy to push back if proven useful.

So there are two problems occurring:
1. AccessViolations are being randomly thrown when library is used heavily (teeth pulling to debug)
Theory: SFML resources are being garbage collected on the gc thread instead of main thread causing some interesting race conditions (I assume SFML backend is not threadsafe?)

I will solve this by marking the objects for disposal in the gc thread and afterwards dispose them on the main thread.

2. I get a heavy mem leak in the minimal code snippet posted earlier on this thread
Theory: Might be fixed by #1 if the leak is caused by AccessViolations. But regardless; finalizers are not guaranteed to be run and this is a perfect usage example for SafeHandles (see http://msdn.microsoft.com/en-us/library/ms228970(v=vs.110).aspx ).

I will add SafeHandles to make sure everything is cleaned up.

What are your thoughts on these approaches?

Title: Re: System.AccessViolation
Post by: myl on January 09, 2014, 03:30:02 pm
I have implemented the fixes all in ObjectBase, but also a static call in DispatchEvents to ObjectBase.DisposeGarbageCollectedObjects().

The leak is now gone. I get no AccessViolations, but due to their random nature It will take longer to confirm they have truly disappeared.

myl
Title: Re: System.AccessViolation
Post by: myl on January 20, 2014, 12:16:44 pm
Running tests on around 230 systems (6 different types of hardware configurations) for the past 11 days, I have received AccessViolations 2 times in total. Before my fixes I had about 20 times per day consistently. I can confirm mem leak issues completely gone.

Let me know if you are interested in the implementation.

myl
Title: Re: System.AccessViolation
Post by: krzat on January 20, 2014, 06:33:37 pm
I'm interested. Fork on Github/Bitbucket would be nice.
Title: Re: System.AccessViolation
Post by: myl on January 25, 2014, 10:36:27 am
Sorry for the slow response time. The implementation is up at
https://github.com/myrup/SFML.Net/
Comments welcome :)

myl
Title: Re: System.AccessViolation
Post by: krzat on January 25, 2014, 06:49:17 pm
1. Do you think it's necessary to track all SFML objects? I think that only OpenGL objects(Texture, Font, etc.) should be disposed in main thread.
2. Have you tried ConcurrentQueue<T> ? Perhaps it would be more efficient.
3. Maybe ObjectBase and ObjectBaseSafeHandle could be merged together?
Title: Re: System.AccessViolation
Post by: myl on January 25, 2014, 08:00:53 pm
1. Good point, I'm not sure which objects are threadsafe and which not, It might be worth making another subclass. For now better too many objects disposed than too few! :)

2. As far as I can tell that's a .Net 4 feature and Sfml should be .Net 2 compatible

3. That would make a lot of sense, I'll be doing that.
Title: Re: System.AccessViolation
Post by: myl on January 26, 2014, 01:42:43 pm
The merged version is up now, and I created a new pull request for Laurent.

myl
Title: Re: System.AccessViolation
Post by: myl on May 26, 2014, 11:18:57 am
Update: The last remaining AccessViolations dissappeared after I started using another texture constructor:

https://github.com/SFML/SFML.Net/pull/60

myl
Title: Re: System.AccessViolation
Post by: myl on May 27, 2014, 02:31:04 pm
Update: The last remaining AccessViolations dissappeared after I started using another texture constructor:

https://github.com/SFML/SFML.Net/pull/60

myl
Merged in master.