Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Screenshot severe memory leak #7

Closed
remcoros opened this issue Jan 14, 2014 · 1 comment
Closed

Screenshot severe memory leak #7

remcoros opened this issue Jan 14, 2014 · 1 comment

Comments

@remcoros
Copy link

Hey,

I don't know if you're still active on this project, but I have been playing with your code and found a severe memory leak.

The Screenshot (MarshalByRefObject) object is never released and it doesn't implement IDisposable.

If capturing a lot of screenshots, memory in the target process keeps growing.

In my case, this resulted in a OOM exception after ~30 seconds of getting consecutive screenshots.

Fix is simple, implement IDisposable, and call RemotingServices.Disconnect(this).

Then, make sure to call Dispose (or the using() construct) in the client application.

public class Screenshot : MarshalByRefObject, IDisposable
{
    private bool _disposed;

    public Screenshot(Guid requestId, byte[] capturedBitmap)
    {
        _requestId = requestId;
        _capturedBitmap = capturedBitmap;
    }

    ~Screenshot()
    {
        Dispose(false);
    }

    /// <summary>
    /// Disconnects the remoting channel(s) of this object and all nested objects.
    /// </summary>
    private void Disconnect()
    {
        RemotingServices.Disconnect(this);
    }

    [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
    public override object InitializeLifetimeService()
    {
        //
        // Returning null designates an infinite non-expiring lease.
        // We must therefore ensure that RemotingServices.Disconnect() is called when
        // it's no longer needed otherwise there will be a memory leak.
        //
        return null;

        //var lease = (ILease)base.InitializeLifetimeService();
        //if (lease.CurrentState == LeaseState.Initial)
        //{
        //    lease.InitialLeaseTime = TimeSpan.FromSeconds(2);
        //    lease.SponsorshipTimeout = TimeSpan.FromSeconds(5);
        //    lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
        //}
        //return lease;
    }

    Guid _requestId;
    public Guid RequestId
    {
        get
        {
            return _requestId;
        }
    }

    byte[] _capturedBitmap;
    public byte[] CapturedBitmap
    {
        get
        {
            return _capturedBitmap;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                Disconnect();
            }
            _disposed = true;
        }
    }
}

Hope that helps.

@justinstenning
Copy link
Owner

Thanks,

Someone else pointed this out also, I just didn't have time to address it
yet.

I plan to do some major overhauls of the project in the coming months and
will incorporate your fix (or if you want to submit a fix To github I will
merge it in).

Cheers,
Justin

On Wednesday, 15 January 2014, Remco Ros wrote:

Hey,

I don't know if you're still active on this project, but I have been
playing with your code and found a severe memory leak.

The Screenshot (MarshalByRefObject) object is never released and it
doesn't implement IDisposable.

If capturing a lot of screenshots, memory in the target process keeps
growing.

In my case, this resulted in a OOM exception after ~30 seconds of getting
consecutive screenshots.

Fix is simple, implement IDisposable, and call
RemotingServices.Disconnect(this).

Then, make sure to call Dispose (or the using() construct) in the client
application.

public class Screenshot : MarshalByRefObject, IDisposable
{
private bool _disposed;

public Screenshot(Guid requestId, byte[] capturedBitmap)
{
    _requestId = requestId;
    _capturedBitmap = capturedBitmap;
}

~Screenshot()
{
    Dispose(false);
}

/// <summary>
/// Disconnects the remoting channel(s) of this object and all nested objects.
/// </summary>
private void Disconnect()
{
    RemotingServices.Disconnect(this);
}

[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
public override object InitializeLifetimeService()
{
    //
    // Returning null designates an infinite non-expiring lease.
    // We must therefore ensure that RemotingServices.Disconnect() is called when
    // it's no longer needed otherwise there will be a memory leak.
    //
    return null;

    //var lease = (ILease)base.InitializeLifetimeService();
    //if (lease.CurrentState == LeaseState.Initial)
    //{
    //    lease.InitialLeaseTime = TimeSpan.FromSeconds(2);
    //    lease.SponsorshipTimeout = TimeSpan.FromSeconds(5);
    //    lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
    //}
    //return lease;
}

Guid _requestId;
public Guid RequestId
{
    get
    {
        return _requestId;
    }
}

byte[] _capturedBitmap;
public byte[] CapturedBitmap
{
    get
    {
        return _capturedBitmap;
    }
}

public void Dispose()
{
    GC.SuppressFinalize(this);
    Dispose(true);
}

protected virtual void Dispose(bool disposing)
{
    if (_disposed)
        return;

    Disconnect();
    _disposed = true;
}

}

Hope that helps.


Reply to this email directly or view it on GitHubhttps://github.com//issues/7
.

3bagorion33 pushed a commit to 3bagorion33/Direct3DHook that referenced this issue Aug 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants