ScriptService execute eating memory - c#

When I run Execute on a ScriptService run request, it takes some memory and fails to release it. Testing this by running on monodevelop on a Raspberry Pi shows the memory rising at an alarming rate, and will eventually crash the program. The GC.Collect was an attempt at re-claiming this memory. Is there any insight into what I am doing wrong?
public MainWindow() : base(Gtk.WindowType.Toplevel)
{
Build();
while (true)
{
getDashRow();
Thread.Sleep(1000);
Console.WriteLine("Total available memory before collection: {0:N0}", System.GC.GetTotalMemory(false));
System.GC.Collect();
Console.WriteLine("Total available memory collection: {0:N0}", System.GC.GetTotalMemory(true));
}
}
private int getDashRow()
{
ScriptsResource.RunRequest runreq;
DriveService driveservice;
ExecutionRequest exrequest;
Console.WriteLine("getDashRow");
int retval = 0;
exrequest = new ExecutionRequest();
exrequest.Function = "getMacRow";
IList<object> parameters = new List<object>();
parameters.Add(spreadsheetname);
exrequest.Parameters = parameters;
exrequest.DevMode = false;
try
{
// run a Google Apps Script function on the online sheet to find number of rows (more efficient)
runreq = scriptservice.Scripts.Run(exrequest, dashscriptid);
// following line consumes the memory
Operation op = runreq.Execute();
retval = Convert.ToInt16(op.Response["result"]);
parameters = null;
exrequest = null;
op = null;
}
catch (Exception ex)
{
Console.WriteLine("getDashRow: " + ex.Message);
}
return retval;
}

I solved this, installing Mono Preview v6.0.0.277 has resolved this problem, memory is now correctly freed up without manually calling GC.Collect().
Related issue which led to the solution

Related

C# ServerManager leaking memory on Windows 7

I have been trying to diagnose a memory leak in a service which only appears on Windows 7/Server 2008 R2. I narrowed it down to where we are using Microsoft.Web.Administration.ServerManager to gather info about the apps in our site. I whittled it down to the console app below, which exhibits the same behavior. It might still be more complex than it needs to be, but I wanted to emulate the behavior of the service as much as possible.
I found a previous question here that was very similar and made the changes suggested in the answers. This appeared to reduce the rate of growth, but it still leaks significantly (under the comments "Original Test" I have commented out code that I changed based on those answers. the "Modified Test" comments indicate the changes I made. I didn't initially have the GC.Collect call in, and when I ran this on a Windows 10 system, it grew for quite some time before the garbage collection kicked in. With the GC.Collect call in place, it ran without growing on Win 10, but on Win 7 it made no difference.
I ran it under a profiler that indicated the memory being leaked was native, and that the leak was coming from nativerd.dll.
Has anyone encountered a problem like this? I'm new to C# and am still learning how Garbage Collection works, so I'm wondering if there is something I'm doing wrong?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Web.Administration;
namespace ServerManagerLeakTest
{
class Program
{
static void Main(string[] args)
{
Console.Write("Working.");
var me = new MyClass();
me.Run();
}
}
internal class MyClass
{
ServerManagerWrapper _smw = new ServerManagerWrapper();
public void Run()
{
while (true)
{
var t = Task.Run(async delegate
{
DoWork();
await Task.Delay(1000);
});
try
{
t.Wait();
}
catch (Exception e)
{
Console.Write("Main Exception: " + e.Message);
}
Console.Write(".");
}
}
public void DoWork()
{
try
{
var data = _smw.GetWebApps().ToList();
data.Clear();
}
catch (Exception e)
{
Console.Write("DoWork Exception: " + e.Message);
}
}
}
internal class ServerManagerWrapper
{
public List<int> GetWebApps()
{
List<int> result = new List<int>() { };
// Original Test
//
// using (var serverManager = new ServerManager())
// {
// foreach (var site in serverManager.Sites)
// {
// result.AddRange(GetWebApps(site));
// }
//}
// Modified Test
var serverManager = new ServerManager();
foreach (var site in serverManager.Sites)
{
result.AddRange(GetWebApps(site));
}
serverManager.Dispose();
serverManager = null;
System.GC.Collect();
return result;
}
private IEnumerable<int> GetWebApps(Site site)
{
// Original Test
//
//for (var application in site.Applications)
//{
// yield return application.GetHashCode();
//}
// Modified Test
List<int> result = new List<int>() { };
for (int i = 0; i < site.Applications.Count; i++)
{
result.Add(site.Applications[i].GetHashCode());
}
return result;
}
}
}
Answer provided in comments from #Lex Li.
Move the check to a separate process. Calling IIS REST API, PowerShell, or even appcmd and parse the result. Let the leak be out of your own service.

GC Behavior Inconsistent Between 32-bit and 64-bit Applications

I have noticed inconsistent behavior from the GC when compiling console applications under both 32-bit and 64-bit in .Net 4.0 using VS 2013.
Consider the following code:
class Test
{
public static bool finalized = false;
~Test()
{
finalized = true;
}
}
and in Main() ...
var t = new Test();
t = null;
GC.Collect();
GC.WaitForPendingFinalizers();
if (!Test.finalized)
throw new Exception("oops!");
When running in 64-bit (debug) mode this works every time without fail; however, running in 32-bit mode I cannot force this object to get collected (even if I create more objects and wait a period of time, which I have tried).
Does anyone have any ideas as to why this is? It's causing me trouble when trying to debug some code that must deal with releasing unmanaged proxy data for the 32-bit version of the assemblies. There's a lot of objects in 32-bit mode that just sit there until a long time later (no so in 64-bit).
I'm trying to debug something in 32-bit mode, but the finalizers are not getting called (at least, not by force). The objects just sit there and never get collected (I can see all the weak references still having a value). In 64-bit mode, all the weak references are cleared as expected, and all finalizers get called.
Note: Though the code above is on a very small scale, I have noticed in 32-bit mode many more objects stuck in the GC until more objects get created later (even when "Collect" and "WaitForPendingFinalizers" is called). This is never the case in 64-bit mode. I have one user wondering why so many objects where not getting collected, which caused me to investigate, to which I found out that everything seems to work better in 64-bit mode than 32. Just trying to understand why.
Edit: Here is better code to show the differences:
class Program
{
class Test
{
public static bool Finalized = false;
public int ID;
public Test(int id)
{
ID = id;
}
~Test()
{ // <= Put breakpoint here
Finalized = true;
Console.WriteLine("Test " + ID + " finalized.");
}
}
static List<WeakReference> WeakReferences = new List<WeakReference>();
public static bool IsNet45OrNewer()
{
// Class "ReflectionContext" exists from .NET 4.5 onwards.
return Type.GetType("System.Reflection.ReflectionContext", false) != null;
}
static void Main(string[] args)
{
Console.WriteLine("Is 4.5 or newer: " + IsNet45OrNewer());
Console.WriteLine("IntPtr: " + IntPtr.Size + Environment.NewLine);
Console.WriteLine("Creating the objects ...");
for (var i = 0; i < 10; ++i)
WeakReferences.Add(new WeakReference(new Test(i)));
Console.WriteLine("Triggering collect ...");
GC.Collect();
Console.WriteLine("Triggering finalizers ..." + Environment.NewLine);
GC.WaitForPendingFinalizers();
Console.WriteLine(Environment.NewLine + "Checking for objects still not finalized ...");
bool ok = true;
for (var i = 0; i < 10; ++i)
if (WeakReferences[i].IsAlive)
{
var test = (Test)WeakReferences[i].Target;
if (test != null)
Console.WriteLine("Weak references still exist for Test " + test.ID + ".");
ok = false;
}
if (ok)
Console.WriteLine("All Test objects successfully collected and finalized.");
Console.WriteLine(Environment.NewLine + "Creating more objects ...");
for (var i = 0; i < 10; ++i)
WeakReferences.Add(new WeakReference(new Test(i)));
Console.WriteLine("Triggering collect ...");
GC.Collect();
Console.WriteLine("Triggering finalizers ..." + Environment.NewLine);
GC.WaitForPendingFinalizers();
Console.WriteLine(Environment.NewLine + "Checking for objects still not finalized ...");
ok = true;
for (var i = 0; i < 10; ++i)
if (WeakReferences[i].IsAlive)
{
var test = (Test)WeakReferences[i].Target;
if (test != null)
Console.WriteLine("Weak references still exist for Test " + test.ID + ".");
ok = false;
}
if (ok)
Console.WriteLine("All Test objects successfully collected and finalized.");
Console.WriteLine(Environment.NewLine + "Done.");
Console.ReadKey();
}
}
It works in 64-bit, but not in 32-bit. On my system, "Test #9" never gets collected (a weak reference remains), even after creating more objects, and trying a second time.
FYI: The main reason for asking the question is because I have a \gctest option in my console to test garbage collection between V8.Net and the underlying V8 engine on the native side. It works in 64-bit, but not 32.
No repro on VS2013 + .NET 4.5 on x86 and x64:
class Program
{
class Test
{
public readonly int I;
public Test(int i)
{
I = i;
}
~Test()
{
Console.WriteLine("Finalizer for " + I);
}
}
static void Tester()
{
var t = new Test(1);
}
public static bool IsNet45OrNewer()
{
// Class "ReflectionContext" exists from .NET 4.5 onwards.
return Type.GetType("System.Reflection.ReflectionContext", false) != null;
}
static void Main(string[] args)
{
Console.WriteLine("Is 4.5 or newer: " + IsNet45OrNewer());
Console.WriteLine("IntPtr: " + IntPtr.Size);
var t = new Test(2);
t = null;
new Test(3);
Tester();
Console.WriteLine("Pre GC");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Post GC");
Console.ReadKey();
}
}
Note that (as noticed by #Sriram Sakthivel), there could be "ghost" copies of your variable around, that have their lifespan extended until the end of the method (when you compile the code in Debug mode or you have a debugger attached (F5 instead of Ctrl+F5), the lifespan of your variables is extended until the end of the method to ease debugging)
For example object initialization (when you do something like new Foo { I = 5 }) creates an hidden local variable.

Memory Leak in WMI and possible solution

So we have a memory leak in our application and we think it's from WMI calls.
This is the code where we think is the leak:
private ThermalInfo()
{
// ============== Temperature
var mgmtTempScope = new ManagementScope(#"\root\WMI");
var oQuery = new ObjectQuery("select * from MSAcpi_ThermalZoneTemperature");
ManagementObjectSearcher oTempSearch = null;
ManagementObjectCollection collection = null;
try
{
oTempSearch = new ManagementObjectSearcher(mgmtTempScope, oQuery);
collection = oTempSearch.Get();
foreach (var obj in collection)
{
mTemperature = Convert.ToDouble(obj.Properties["CurrentTemperature"].Value) / 10 - 273.2;
mValid = true;
obj.Dispose();
}
}
catch //(Exception ex)
{
// Not supported
mTemperature = 0;
mValid = false;
}
finally
{
if (collection != null)
collection.Dispose();
if (oTempSearch != null)
oTempSearch.Dispose();
FlushMemory();
}
}
And here the FlushMemory():
[DllImportAttribute("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern int SetProcessWorkingSetSize(IntPtr process, int minimumWorkingSetSize, int maximumWorkingSetSize);
public static void FlushMemory()
{
GC.Collect();
GC.WaitForPendingFinalizers();
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);
}
}
Our Application (it's actually a service) kept growing and growing - and the only thing that it was doing was calling this Method and setting the mTemperatur and mValid. With the FlushMemory Call the leak stopped and i could run the service the whole night without any growth in memory.
The only problem i have now is that the service won't let itself stop anymore. Everytime i want to stop the service it's never stopping and i always have to forcestop it with taskkill or the taskmanager.
Could someone please help me with this? Also how can i avoid the leak in the WMI calls? I've got w8.1 so there shouldn'T be a problem anymore but i guess there is...
we are seeing similar problem: ManagementClass, etc creates large memory leak, even with proper use of using(..){..} and Dispose().
Searching stackoverflow and elsewhere we see it is a common problem.
Calling GC.WaitForPendingFinalizers() once, which is part of the FlushMemory() above, is enough to fix it (GC.Collect() is not needed)
though we do not consider it a solution really, just a workaround.

memory management in C# for high speed applications

I am building an application that processes an incoming image from file or buffer and outputs results in the form of an array or doubles of fixed size. The application needs to be relatively quick. I ran into a problem with cycle time. I started recording cycle time while processing one image and it went from the minimum at 65ms and gradually started increasing to all the way 500ms which is way too slow. Sure enough, I checked on the memory usage and it was steadily increasing as well.
I'm running GC after every cycle and dumping unused variable as ofter as possible. I don't create new objects within the processing loop. Image processing is done on its own thread so that all the resources get dumped. It seems the majority of the cycle time increase happens when I'm pulling the image from file. What could I be missing?
here's the rough code, the full thing is pretty large. Main Function
private void button4_Click(object sender, EventArgs e)
{
Stopwatch sw = new Stopwatch();
sw.Start();
cogDisplay1.Image = null;
ImageFromFile.Operator.Open(Properties.Settings.Default.ImageFile, CogImageFileModeConstants.Read);
ImageFromFile.Run();
cogDisplay1.Image = ImageFromFile.OutputImage;
cogDisplay1.AutoFit = true;
Thread t = new Thread(Vision);
t.Start();
textBox3.Clear();
sw.Stop();
textBox3.AppendText(sw.ElapsedMilliseconds.ToString() + Environment.NewLine + "TS: " + t.ThreadState.ToString());
textBox3.AppendText("GC" + GC.GetTotalMemory(true).ToString());
GC.Collect(GC.MaxGeneration , GCCollectionMode.Forced, false);
}
Image Processing
public void Vision()
{
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
AlignmentParams.ApproximateNumberToFind = 1;
AlignmentParams.SearchRegionMode = 0;
AlignmentResult = AlignmentPat.Execute(cogDisplay1.Image as CogImage8Grey, null , AlignmentParams);
Fixture.InputImage = cogDisplay1.Image;
Fixture.RunParams.UnfixturedFromFixturedTransform = AlignmentResult[0].GetPose();
Fixture.Run();
AlignmentResult = null;
#region FindLineTools
#endregion
#region FindEllipse
#endregion
sw.Stop();
SetText("V" + sw.ElapsedMilliseconds.ToString() + Environment.NewLine);
}
catch (Exception err)
{
SetText(Environment.NewLine + "***********Error***********" + Environment.NewLine);
SetText(err.ToString() + Environment.NewLine);
SetText("***************************" + Environment.NewLine);
}
}
First, I would recommend to post a cleaned-up code for better readability (remove all commented-off stuff). Second, focus only on essential part, namely: your problem is memory overuse/leak due to heavy image processing (correct if wrong). Therefore, in your thread named Vision de-reference the image objects and set them to null immediately after processing completion (as mentioned above, GC is not a big help in your case). The concept briefly demonstrated by following code snippet:
public void Vision()
{
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
AlignmentParams.ApproximateNumberToFind = 1;
AlignmentParams.SearchRegionMode = 0;
AlignmentResult = AlignmentPat.Execute(cogDisplay1.Image as CogImage8Grey, null , AlignmentParams);
Fixture.InputImage = cogDisplay1.Image;
Fixture.RunParams.UnfixturedFromFixturedTransform = AlignmentResult[0].GetPose();
Fixture.Run();
AlignmentResult = null;
// your coding stuff
sw.Stop();
SetText("V" + sw.ElapsedMilliseconds.ToString() + Environment.NewLine);
}
catch (Exception err)
{
SetText(Environment.NewLine + "***********Error***********" + Environment.NewLine);
SetText(err.ToString() + Environment.NewLine);
SetText("***************************" + Environment.NewLine);
}
finally{Fixture.InputImage=null}
Don't call GC.Collect. Let the VM decide when it is out of memory and must do the collection. You typically are not in a good position to decide the best time for a GC.Collect unless your running some other heartbeat or idle watching threads.
Secondly, ensure that whatever resources you're receiving from the method calls are being Disposed. Setting variables to NULL do NOT do this, you should be explicitly calling Dispose or within a Using block:
using(SomeResource resource = Class.GiveMeResource("image.png"))
{
int width = resource.Width;
int height = resource.Height;
Console.Write("that image has {0} pixels", width*height);
} //implicitly calls IDisposable.Dispose() here.
You also need to do some memory and call profiling to detect where, if any, leaks exist.

c# memory leak in loop

public void DoPing(object state)
{
string host = state as string;
m_lastPingResult = false;
while (!m_pingThreadShouldStop.WaitOne(250))
{
Ping p = new Ping();
try
{
PingReply reply = p.Send(host, 3000);
if (reply.Status == IPStatus.Success)
{
m_lastPingResult = true;
}
else
{
m_lastPingResult = false;
}
}
catch
{
}
numping = numping + 1;
}
}
Any idea why this code gives me a memory leak? I can see it's this code as changing the wait value to smaller or larger values increases the rate of the memory usage. Does any one have any idea how to resolve it? or how to see what part of the code is causing it?
In some garbage collected languages, there is a limitation that the object isn't collected if the method that created it still hasn't exited.
I believe .net works this way in debug mode. Quoting from this article; note the bolded statement.
http://www.simple-talk.com/dotnet/.net-framework/understanding-garbage-collection-in-.net/
A local variable in a method that is currently running is considered
to be a GC root. The objects referenced by these variables can always
be accessed immediately by the method they are declared in, and so
they must be kept around. The lifetime of these roots can depend on
the way the program was built. In debug builds, a local variable lasts
for as long as the method is on the stack. In release builds, the JIT
is able to look at the program structure to work out the last point
within the execution that a variable can be used by the method and
will discard it when it is no longer required. This strategy isn’t
always used and can be turned off, for example, by running the program
in a debugger.
Garbage collection only happens when there is memory pressure, thus just seeing your memory usage go up doesn't mean there is a memory leak and in this code I don't see how there could be a legitimate leak. You can add
GC.Collect();
GC.WaitForPendingFinalizers();
to double check but shouldn't leave that in production.
Edit: someone in comments pointed out that Ping is Disposable. not calling dispose can cause leaks that will eventually get cleaned up but may take a long time and cause non memory related problems.
Add a finally statement to your try-catch, like this:
catch() {}
finally
{
Ping.Dispose();
}
using(var p = new Ping())
{
try
{
var reply = p.Send(host, 3000);
if (reply.Status == IPStatus.Success)
_lastPingResult = true;
else
_lastPingResult = false;
}
catch(Exception e)
{
//...
}
}
This can be used from a static Class:
public static bool testNet(string pHost, int pTimeout)
{
Ping p = new Ping();
bool isNetOkay = false;
int netTries = 0;
do
{
PingReply reply = p.Send(pHost, pTimeout);
if (reply.Status == IPStatus.Success)
{
isNetOkay = true;
break;
}
netTries++;
} while (netTries < 4);
//Void memory leak
p.Dispose();
return isNetOkay;
}

Categories