-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Prevent Repository objects from being prematurely GCed #1337
Conversation
By wrapping the Repository object in a using statement we prevent it from being being GCed when there are only native pointers to it.
Use with a using statement.
Dispose of Repository object.
I got the following when trying to create a new PR:
|
// CommitMessage doesn't keep a reference to Repository | ||
using (var repo = gitService.GetRepository(repository.LocalPath)) | ||
{ | ||
return gitClient.GetMessagesForUniqueCommits(repo, baseBranch, compareBranch, maxCommits).ToObservable(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ToObservable / threading issue.
08afc5c
to
4db51b2
Compare
using (var repo = gitService.GetRepository(repository.LocalPath)) | ||
{ | ||
var result = GetLocalBranchesInternal(repository, repo, pullRequest).Select(x => new BranchModel(x, repository)); | ||
return result.ToObservable(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@grokys I have a bad feeling about this one. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm yeah, should probably call ToList()
on result
here.
For reference, the other option is to destroy the repo
with a Using
operator, I don't think that'd be necessary here however.
We don't want to dispose of Repository while still enumerating its branches.
I'm seeing an issue where after clicking the checkout link, the checkout appears to succeed but the UI doesn't update. Any idea what might be causing that? |
Not seen that before. Does it happen on master? |
@grokys I thought this was likely an issue introduced with this PR. Haven't seen it on master before. Update, this is also happening on master. 😕 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 LGTM! Just a small nit about a commented-out line.
repository.Dispose(); | ||
|
||
// NOTE: IDiffService doesn't own the Repository object | ||
//repository.Dispose(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather remove this commented-out line.
The Bug
The following code can fail on the
repo.RetrieveStatus()
line with anAccessViolationException
:This is because
RetrieveStatus
creates a native pointer to theRepository
object and but doesn't hold on to a managed reference. This allows theRepository
object to be GCed beforeRetrieveStatus
has finished with the native pointer.To vaoid random crashes, we need to be careful to keep a reference to
Repository
when calling its methods. The above code can be fixed like this:Alternatively since the
Repository
object implementsIDisposable
, the following will keep a reference and dispose of it afterwards:This PR wraps all temporary references to a
Repository
object in ausing
statement.Possible Gotchas
Release
configuration (inDebug
configuration, references are held on to for longer and this bug doesn't occur).Repository
objects. For example here, we need to make sure thatCommitMessage
doesn't cache a reference to the disposedRepository
object:VisualStudio/src/GitHub.App/Services/PullRequestService.cs
Line 101 in 7fb09a3
Fixes #1315
See also: libgit2/libgit2sharp#1513