|From: James J Greensky <jame.j.greensky@intel.com>
|Date: Wed, 5 Aug 2009 09:51:52 -0700 |Subject: [PATCH] Closed two major memory leaks for scripted objects | |Two major memory leaks for the scripted objects were fixed |- One leak had to do with remoting acrossing app domains. When a script and | its controlling agent communicate across an application boundary, it calls | functions on a stub proxy object that then invokes the remote method on | the object in the other app domain. These stub objects (two for each script) | were setup to have infinate lifetimes and were never being garbage collected. |- The second leak was the result of adding a scene object part instance method | to a scene event and never removing it. This cause the event's delegate list | to maintain a link to that object which is then never freed as the scene event | object is never destroyed. Patch applied, please direct feedback to me. Possible issue: Longtime idle scripts like vendors may fail.arthursv
parent
eb9d584ee0
commit
91f6898b26
|
@ -953,11 +953,12 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
// this lets us keep track of nasty script events like timer, etc.
|
// this lets us keep track of nasty script events like timer, etc.
|
||||||
public void TriggerTimerEvent(uint objLocalID, double Interval)
|
public void TriggerTimerEvent(uint objLocalID, double Interval)
|
||||||
{
|
{
|
||||||
handlerScriptTimerEvent = OnScriptTimerEvent;
|
throw new NotImplementedException("TriggerTimerEvent was thought to be not used anymore and the registration for the event from scene object part has been commented out due to a memory leak");
|
||||||
if (handlerScriptTimerEvent != null)
|
//handlerScriptTimerEvent = OnScriptTimerEvent;
|
||||||
{
|
//if (handlerScriptTimerEvent != null)
|
||||||
handlerScriptTimerEvent(objLocalID, Interval);
|
//{
|
||||||
}
|
// handlerScriptTimerEvent(objLocalID, Interval);
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -3673,14 +3673,14 @@ if (m_shape != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0)
|
//if ((GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0)
|
||||||
{
|
//{
|
||||||
m_parentGroup.Scene.EventManager.OnScriptTimerEvent += handleTimerAccounting;
|
// m_parentGroup.Scene.EventManager.OnScriptTimerEvent += handleTimerAccounting;
|
||||||
}
|
//}
|
||||||
else
|
//else
|
||||||
{
|
//{
|
||||||
m_parentGroup.Scene.EventManager.OnScriptTimerEvent -= handleTimerAccounting;
|
// m_parentGroup.Scene.EventManager.OnScriptTimerEvent -= handleTimerAccounting;
|
||||||
}
|
//}
|
||||||
|
|
||||||
LocalFlags=(PrimFlags)objectflagupdate;
|
LocalFlags=(PrimFlags)objectflagupdate;
|
||||||
|
|
||||||
|
|
|
@ -41,5 +41,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
Dictionary<string,Object> GetVars();
|
Dictionary<string,Object> GetVars();
|
||||||
void SetVars(Dictionary<string,Object> vars);
|
void SetVars(Dictionary<string,Object> vars);
|
||||||
void ResetVars();
|
void ResetVars();
|
||||||
|
|
||||||
|
void Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,14 +119,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
AsyncCommands = new AsyncCommandManager(ScriptEngine);
|
AsyncCommands = new AsyncCommandManager(ScriptEngine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Object never expires
|
|
||||||
public override Object InitializeLifetimeService()
|
public override Object InitializeLifetimeService()
|
||||||
{
|
{
|
||||||
ILease lease = (ILease)base.InitializeLifetimeService();
|
ILease lease = (ILease)base.InitializeLifetimeService();
|
||||||
|
|
||||||
if (lease.CurrentState == LeaseState.Initial)
|
if (lease.CurrentState == LeaseState.Initial)
|
||||||
{
|
{
|
||||||
lease.InitialLeaseTime = TimeSpan.Zero;
|
lease.InitialLeaseTime = TimeSpan.FromMinutes(1.0);
|
||||||
|
lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0);
|
||||||
|
lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0);
|
||||||
}
|
}
|
||||||
return lease;
|
return lease;
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,16 +159,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Never expire this object
|
|
||||||
//
|
|
||||||
public override Object InitializeLifetimeService()
|
public override Object InitializeLifetimeService()
|
||||||
{
|
{
|
||||||
ILease lease = (ILease)base.InitializeLifetimeService();
|
ILease lease = (ILease)base.InitializeLifetimeService();
|
||||||
|
|
||||||
if (lease.CurrentState == LeaseState.Initial)
|
if (lease.CurrentState == LeaseState.Initial)
|
||||||
{
|
{
|
||||||
lease.InitialLeaseTime = TimeSpan.Zero;
|
lease.InitialLeaseTime = TimeSpan.FromMinutes(1.0);
|
||||||
|
lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0);
|
||||||
|
lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0);
|
||||||
}
|
}
|
||||||
return lease;
|
return lease;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ using log4net;
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
{
|
{
|
||||||
public class Executor : MarshalByRefObject
|
public class Executor
|
||||||
{
|
{
|
||||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
@ -89,26 +89,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
initEventFlags();
|
initEventFlags();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Make sure our object does not timeout when in AppDomain. (Called by ILease base class)
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override Object InitializeLifetimeService()
|
|
||||||
{
|
|
||||||
//m_log.Debug("Executor: InitializeLifetimeService()");
|
|
||||||
// return null;
|
|
||||||
ILease lease = (ILease)base.InitializeLifetimeService();
|
|
||||||
|
|
||||||
if (lease.CurrentState == LeaseState.Initial)
|
|
||||||
{
|
|
||||||
lease.InitialLeaseTime = TimeSpan.Zero; // TimeSpan.FromMinutes(1);
|
|
||||||
// lease.SponsorshipTimeout = TimeSpan.FromMinutes(2);
|
|
||||||
// lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
|
|
||||||
}
|
|
||||||
return lease;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public scriptEvents GetStateEventFlags(string state)
|
public scriptEvents GetStateEventFlags(string state)
|
||||||
{
|
{
|
||||||
//m_log.Debug("Get event flags for " + state);
|
//m_log.Debug("Get event flags for " + state);
|
||||||
|
|
|
@ -32,7 +32,7 @@ using LSLInteger = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
{
|
{
|
||||||
public partial class ScriptBaseClass : MarshalByRefObject
|
public partial class ScriptBaseClass
|
||||||
{
|
{
|
||||||
// LSL CONSTANTS
|
// LSL CONSTANTS
|
||||||
public static readonly LSLInteger TRUE = new LSLInteger(1);
|
public static readonly LSLInteger TRUE = new LSLInteger(1);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.Remoting;
|
||||||
using System.Runtime.Remoting.Lifetime;
|
using System.Runtime.Remoting.Lifetime;
|
||||||
using System.Security.Permissions;
|
using System.Security.Permissions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
@ -34,26 +35,23 @@ using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using OpenSim.Region.ScriptEngine.Interfaces;
|
using OpenSim.Region.ScriptEngine.Interfaces;
|
||||||
using OpenSim.Region.ScriptEngine.Shared;
|
using OpenSim.Region.ScriptEngine.Shared;
|
||||||
|
using OpenSim.Region.ScriptEngine.Shared.Api.Runtime;
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
{
|
{
|
||||||
public partial class ScriptBaseClass : MarshalByRefObject, IScript
|
public partial class ScriptBaseClass : MarshalByRefObject, IScript
|
||||||
{
|
{
|
||||||
private Dictionary<string, MethodInfo> inits = new Dictionary<string, MethodInfo>();
|
private Dictionary<string, MethodInfo> inits = new Dictionary<string, MethodInfo>();
|
||||||
|
private ScriptSponsor m_sponser;
|
||||||
|
|
||||||
// Object expires if we don't keep it alive
|
|
||||||
// sponsor will be added on object load
|
|
||||||
[SecurityPermissionAttribute(SecurityAction.Demand,
|
|
||||||
Flags = SecurityPermissionFlag.Infrastructure)]
|
|
||||||
public override Object InitializeLifetimeService()
|
public override Object InitializeLifetimeService()
|
||||||
{
|
{
|
||||||
ILease lease = (ILease)base.InitializeLifetimeService();
|
ILease lease = (ILease)base.InitializeLifetimeService();
|
||||||
if (lease.CurrentState == LeaseState.Initial)
|
if (lease.CurrentState == LeaseState.Initial)
|
||||||
{
|
{
|
||||||
lease.InitialLeaseTime = TimeSpan.Zero;
|
lease.InitialLeaseTime = TimeSpan.FromMinutes(1.0);
|
||||||
// lease.InitialLeaseTime = TimeSpan.FromMinutes(1);
|
lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0);
|
||||||
// lease.SponsorshipTimeout = TimeSpan.FromMinutes(2);
|
lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0);
|
||||||
// lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
|
|
||||||
}
|
}
|
||||||
return lease;
|
return lease;
|
||||||
}
|
}
|
||||||
|
@ -66,7 +64,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
public ScriptBaseClass()
|
public ScriptBaseClass()
|
||||||
{
|
{
|
||||||
m_Executor = new Executor(this);
|
m_Executor = new Executor(this);
|
||||||
|
@ -81,6 +78,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
inits[type] = mi;
|
inits[type] = mi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_sponser = new ScriptSponsor();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Executor m_Executor = null;
|
private Executor m_Executor = null;
|
||||||
|
@ -112,6 +111,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
if (!inits.ContainsKey(api))
|
if (!inits.ContainsKey(api))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
ILease lease = (ILease)RemotingServices.GetLifetimeService(data as MarshalByRefObject);
|
||||||
|
lease.Register(m_sponser);
|
||||||
|
|
||||||
MethodInfo mi = inits[api];
|
MethodInfo mi = inits[api];
|
||||||
|
|
||||||
Object[] args = new Object[1];
|
Object[] args = new Object[1];
|
||||||
|
@ -122,6 +124,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
||||||
m_InitialValues = GetVars();
|
m_InitialValues = GetVars();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
m_sponser.Close();
|
||||||
|
}
|
||||||
|
|
||||||
public Dictionary<string, object> GetVars()
|
public Dictionary<string, object> GetVars()
|
||||||
{
|
{
|
||||||
Dictionary<string, object> vars = new Dictionary<string, object>();
|
Dictionary<string, object> vars = new Dictionary<string, object>();
|
||||||
|
|
|
@ -32,15 +32,19 @@ using System.Text;
|
||||||
|
|
||||||
namespace OpenSim.Region.ScriptEngine.Shared.Api.Runtime
|
namespace OpenSim.Region.ScriptEngine.Shared.Api.Runtime
|
||||||
{
|
{
|
||||||
[Serializable]
|
|
||||||
public class ScriptSponsor : MarshalByRefObject, ISponsor
|
public class ScriptSponsor : MarshalByRefObject, ISponsor
|
||||||
{
|
{
|
||||||
// In theory: I execute, therefore I am.
|
private bool m_closed = false;
|
||||||
// If GC collects this class then sponsorship will expire
|
|
||||||
public TimeSpan Renewal(ILease lease)
|
public TimeSpan Renewal(ILease lease)
|
||||||
{
|
{
|
||||||
return TimeSpan.FromMinutes(2);
|
if (!m_closed)
|
||||||
|
return lease.InitialLeaseTime;
|
||||||
|
return TimeSpan.FromTicks(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Close() { m_closed = true; }
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
// For tracing GC while debugging
|
// For tracing GC while debugging
|
||||||
public static bool GCDummy = false;
|
public static bool GCDummy = false;
|
||||||
|
|
|
@ -96,7 +96,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
|
||||||
private string m_CurrentState = String.Empty;
|
private string m_CurrentState = String.Empty;
|
||||||
private UUID m_RegionID = UUID.Zero;
|
private UUID m_RegionID = UUID.Zero;
|
||||||
|
|
||||||
//private ISponsor m_ScriptSponsor;
|
private ScriptSponsor m_ScriptSponsor;
|
||||||
|
private bool m_destroyed = false;
|
||||||
private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>
|
private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>
|
||||||
m_LineMap;
|
m_LineMap;
|
||||||
|
|
||||||
|
@ -261,12 +262,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
|
||||||
Path.GetFileNameWithoutExtension(assembly),
|
Path.GetFileNameWithoutExtension(assembly),
|
||||||
"SecondLife.Script");
|
"SecondLife.Script");
|
||||||
|
|
||||||
// Add a sponsor to the script
|
m_ScriptSponsor = new ScriptSponsor();
|
||||||
// ISponsor scriptSponsor = new ScriptSponsor();
|
ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
|
||||||
// ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as MarshalByRefObject);
|
lease.Register(m_ScriptSponsor);
|
||||||
// lease.Register(scriptSponsor);
|
|
||||||
//m_ScriptSponsor = scriptSponsor;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
@ -449,6 +447,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
|
||||||
{
|
{
|
||||||
ReleaseControls();
|
ReleaseControls();
|
||||||
AsyncCommandManager.RemoveScript(m_Engine, m_LocalID, m_ItemID);
|
AsyncCommandManager.RemoveScript(m_Engine, m_LocalID, m_ItemID);
|
||||||
|
|
||||||
|
m_Script.Close();
|
||||||
|
m_ScriptSponsor.Close();
|
||||||
|
ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
|
||||||
|
lease.Unregister(m_ScriptSponsor);
|
||||||
|
|
||||||
|
m_destroyed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveState()
|
public void RemoveState()
|
||||||
|
@ -884,6 +889,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
|
||||||
|
|
||||||
public void SaveState(string assembly)
|
public void SaveState(string assembly)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
// If we're currently in an event, just tell it to save upon return
|
// If we're currently in an event, just tell it to save upon return
|
||||||
//
|
//
|
||||||
if (m_InEvent)
|
if (m_InEvent)
|
||||||
|
@ -892,6 +899,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Data may not be available as the script has already been destroyed
|
||||||
|
if (m_destroyed == true)
|
||||||
|
return;
|
||||||
|
|
||||||
PluginData = AsyncCommandManager.GetSerializationData(m_Engine, m_ItemID);
|
PluginData = AsyncCommandManager.GetSerializationData(m_Engine, m_ItemID);
|
||||||
|
|
||||||
string xml = ScriptSerializer.Serialize(this);
|
string xml = ScriptSerializer.Serialize(this);
|
||||||
|
|
|
@ -272,6 +272,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
instance.ClearQueue();
|
instance.ClearQueue();
|
||||||
instance.Stop(0);
|
instance.Stop(0);
|
||||||
|
|
||||||
|
// Release events, timer, etc
|
||||||
|
//
|
||||||
|
instance.DestroyScriptInstance();
|
||||||
|
|
||||||
// Unload scripts and app domains
|
// Unload scripts and app domains
|
||||||
// Must be done explicitly because they have infinite
|
// Must be done explicitly because they have infinite
|
||||||
// lifetime
|
// lifetime
|
||||||
|
@ -282,10 +286,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
m_DomainScripts.Remove(instance.AppDomain);
|
m_DomainScripts.Remove(instance.AppDomain);
|
||||||
UnloadAppDomain(instance.AppDomain);
|
UnloadAppDomain(instance.AppDomain);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release events, timer, etc
|
|
||||||
//
|
|
||||||
instance.DestroyScriptInstance();
|
|
||||||
}
|
}
|
||||||
m_Scripts.Clear();
|
m_Scripts.Clear();
|
||||||
m_PrimObjects.Clear();
|
m_PrimObjects.Clear();
|
||||||
|
@ -802,6 +802,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instance.RemoveState();
|
||||||
|
instance.DestroyScriptInstance();
|
||||||
|
|
||||||
m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
|
m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
|
||||||
if (m_DomainScripts[instance.AppDomain].Count == 0)
|
if (m_DomainScripts[instance.AppDomain].Count == 0)
|
||||||
{
|
{
|
||||||
|
@ -809,9 +812,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
||||||
UnloadAppDomain(instance.AppDomain);
|
UnloadAppDomain(instance.AppDomain);
|
||||||
}
|
}
|
||||||
|
|
||||||
instance.RemoveState();
|
|
||||||
instance.DestroyScriptInstance();
|
|
||||||
|
|
||||||
instance = null;
|
instance = null;
|
||||||
|
|
||||||
ObjectRemoved handlerObjectRemoved = OnObjectRemoved;
|
ObjectRemoved handlerObjectRemoved = OnObjectRemoved;
|
||||||
|
|
Loading…
Reference in New Issue