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

Overriding method in bounded class causing memory leak #8321

Open
nrudnyk opened this issue Apr 8, 2020 · 13 comments
Open

Overriding method in bounded class causing memory leak #8321

nrudnyk opened this issue Apr 8, 2020 · 13 comments
Labels
question The issue is a question
Milestone

Comments

@nrudnyk
Copy link

nrudnyk commented Apr 8, 2020

As the title stands, we've faced memory leak, caused by overriding bounded class.
Setup we have:

  • Native Xcode project with 2 classes
  • Xamarin.iOS Bindings Library, which bounds them
  • Consumer project, which also overrides one of the classes

Everything is described and attached below. If you need more information, or anything else I can help to reproduce, found the reason - let me know.

Steps to Reproduce

  1. Run the TestProjectConsumer app
  2. Push ViewController via pressing button.
  3. Press < back to pop back
  4. Memory leak.

Spikes on the memory graph reflects each time view controller was pushed.
Please see some screenshots under the spoiler:

Screenshot 2020-04-08 at 14 24 06 Screenshot 2020-04-08 at 14 48 47 Screenshot 2020-04-08 at 14 24 24

Expected Behavior

  1. Push ViewController with class
  2. Go back(Pop) from it
  3. Memory is free

Actual Behavior

  1. Push ViewController with class
  2. Go back(Pop) from it
  3. There's happens to be a leak

Environment

=== Visual Studio Community 2019 for Mac ===

Version 8.5.2 (build 13)
Installation UUID: 48f6a3ad-d84d-4db4-a6f3-21b06c1343e6
	GTK+ 2.24.23 (Raleigh theme)
	Xamarin.Mac 6.14.1.39 (d16-5 / 30e8706b4)

	Package version: 608000123

=== Mono Framework MDK ===

Runtime:
	Mono 6.8.0.123 (2019-10/1d0d939dc30) (64-bit)
	Package version: 608000123

=== Roslyn (Language Service) ===

3.5.0-beta4-20125-04+1baa0b3063238ed752ad1f0368b1df6b6901373e

=== NuGet ===

Version: 5.4.0.6315

=== .NET Core SDK ===

SDK: /usr/local/share/dotnet/sdk/3.1.200/Sdks
SDK Versions:
	3.1.200
	3.1.102
MSBuild SDKs: /Library/Frameworks/Mono.framework/Versions/6.8.0/lib/mono/msbuild/Current/bin/Sdks

=== .NET Core Runtime ===

Runtime: /usr/local/share/dotnet/dotnet
Runtime Versions:
	3.1.2
	2.1.16

=== Xamarin.Profiler ===

Version: 1.6.13.11
Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler

=== Updater ===

Version: 11

=== Xamarin.Android ===

Not Installed

=== Microsoft Mobile OpenJDK ===

Java SDK: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home
1.8.0_212-release
Android Designer EPL code available here:
https://github.com/xamarin/AndroidDesigner.EPL

=== Android SDK Manager ===

Version: 16.5.0.39
Hash: 6fb4c79
Branch: remotes/origin/d16-5
Build date: 2020-04-02 00:16:12 UTC

=== Android Device Manager ===

Version: 16.5.0.71
Hash: 49194e8
Branch: remotes/origin/d16-5~1
Build date: 2020-04-02 00:16:32 UTC

=== Xamarin Inspector ===

Version: 1.4.3
Hash: db27525
Branch: 1.4-release
Build date: Mon, 09 Jul 2018 21:20:18 GMT
Client compatibility: 1

=== Apple Developer Tools ===

Xcode 11.3.1 (15715)

=== Xamarin.Mac ===

Version: 6.16.0.13 (Visual Studio Community)
Hash: b75deaf82
Branch: d16-5-xcode11.4
Build date: 2020-04-01 21:33:18-0400

=== Xamarin.iOS ===

Version: 13.16.0.13 (Visual Studio Community)
Hash: b75deaf82
Branch: d16-5-xcode11.4
Build date: 2020-04-01 21:33:19-0400

=== Xamarin Designer ===

Version: 16.5.0.471
Hash: 35aa4889d
Branch: remotes/origin/d16-5
Build date: 2020-02-25 00:52:08 UTC

=== Build Information ===

Release ID: 805020013
Git revision: 90b766333e562018f979de04293c097898dafdf4
Build date: 2020-04-02 10:35:07-04
Build branch: release-8.5
Xamarin extensions: 90b766333e562018f979de04293c097898dafdf4

=== Operating System ===

Mac OS X 10.15.3
Darwin 19.3.0 Darwin Kernel Version 19.3.0
    Thu Jan  9 20:58:23 PST 2020
    root:xnu-6153.81.5~1/RELEASE_X86_64 x86_64

Build Logs


Building TestProjectConsumer (Debug|iPhone)
Build started 4/8/2020 3:50:43 PM.
__________________________________________________
Project "/Users/nrudnyk/Downloads/TestProjectAndBindingLib/TestProjectBindingLib/TestProjectBindingLib/TestProjectBindingLib.csproj" (Build target(s)):

Target _GenerateBindings:
  Skipping target "_GenerateBindings" because all output files are up-to-date with respect to the input files.
Target _CompressNativeFrameworkResources:
  Skipping target "_CompressNativeFrameworkResources" because all output files are up-to-date with respect to the input files.
Target _CompressObjCBindingNativeFrameworkResources:
  Skipping target "_CompressObjCBindingNativeFrameworkResources" because it has no inputs.
Target _GenerateCompileInputs:
    /Library/Frameworks/Mono.framework/Versions/6.8.0/lib/mono/msbuild/Current/bin/Microsoft.Common.CurrentVersion.targets(3276,5): warning MSB9004: ManifestResourceWithNoCulture item type is deprecated. Emit EmbeddedResource items instead, with metadata WithCulture='false', Type='Resx', and optional LogicalName.
Done building target "_GenerateCompileInputs" in project "TestProjectBindingLib.csproj".
Target GenerateTargetFrameworkMonikerAttribute:
  Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the input files.
Target CoreCompile:
  Skipping target "CoreCompile" because all output files are up-to-date with respect to the input files.
Target CopyFilesToOutputDirectory:
    TestProjectBindingLib -> /Users/nrudnyk/Downloads/TestProjectAndBindingLib/TestProjectBindingLib/TestProjectBindingLib/bin/Debug/TestProjectBindingLib.dll

Done building project "TestProjectBindingLib.csproj".
__________________________________________________
Project "/Users/nrudnyk/Downloads/TestProjectAndBindingLib/TestProjectBindingLib/TestProjectConsumer/TestProjectConsumer.csproj" (Build target(s)):

Target _BeforeCoreCompileInterfaceDefinitions:
  Skipping target "_BeforeCoreCompileInterfaceDefinitions" because all output files are up-to-date with respect to the input files.
Target _CoreCompileInterfaceDefinitions:
  Skipping target "_CoreCompileInterfaceDefinitions" because all output files are up-to-date with respect to the input files.
Target _BeforeCoreCompileImageAssets:
  Skipping target "_BeforeCoreCompileImageAssets" because all output files are up-to-date with respect to the input files.
Target _CoreCompileImageAssets:
  Skipping target "_CoreCompileImageAssets" because all output files are up-to-date with respect to the input files.
Target _CoreCompileColladaAssets:
  Skipping target "_CoreCompileColladaAssets" because it has no inputs.
Target _BeforeCoreCompileSceneKitAssets:
  Skipping target "_BeforeCoreCompileSceneKitAssets" because it has no inputs.
Target _BeforeCoreCompileSceneKitAssets:
  Skipping target "_BeforeCoreCompileSceneKitAssets" because it has no inputs.
Target _BeforeCoreCompileSceneKitAssets:
  Skipping target "_BeforeCoreCompileSceneKitAssets" because it has no inputs.
Target _CoreCompileSceneKitAssets:
  Skipping target "_CoreCompileSceneKitAssets" because it has no inputs.
Target _BeforeCompileTextureAtlases:
  Skipping target "_BeforeCompileTextureAtlases" because it has no inputs.
Target _BeforeCompileTextureAtlases:
  Skipping target "_BeforeCompileTextureAtlases" because it has no inputs.
Target _BeforeCompileTextureAtlases:
  Skipping target "_BeforeCompileTextureAtlases" because it has no inputs.
Target _CoreCompileTextureAtlases:
  Skipping target "_CoreCompileTextureAtlases" because it has no inputs.
Target _BeforeCompileCoreMLModels:
  Skipping target "_BeforeCompileCoreMLModels" because all output files are up-to-date with respect to the input files.
Target _CoreCompileCoreMLModels:
  Skipping target "_CoreCompileCoreMLModels" because all output files are up-to-date with respect to the input files.
Target _CoreOptimizePngImages:
  Skipping target "_CoreOptimizePngImages" because it has no outputs.
Target _CoreOptimizePropertyLists:
  Skipping target "_CoreOptimizePropertyLists" because it has no inputs.
Target _CoreOptimizeLocalizationFiles:
  Skipping target "_CoreOptimizeLocalizationFiles" because it has no inputs.
Target _GetProjectReferenceTargetFrameworkProperties:
    __________________________________________________
    Project "/Users/nrudnyk/Downloads/TestProjectAndBindingLib/TestProjectBindingLib/TestProjectConsumer/TestProjectConsumer.csproj" is building "/Users/nrudnyk/Downloads/TestProjectAndBindingLib/TestProjectBindingLib/TestProjectBindingLib/TestProjectBindingLib.csproj" (GetTargetFrameworks target(s)):

Target ResolveProjectReferences:
    __________________________________________________
    Project "/Users/nrudnyk/Downloads/TestProjectAndBindingLib/TestProjectBindingLib/TestProjectConsumer/TestProjectConsumer.csproj" is building "/Users/nrudnyk/Downloads/TestProjectAndBindingLib/TestProjectBindingLib/TestProjectBindingLib/TestProjectBindingLib.csproj" (GetTargetPath target(s)):

    __________________________________________________
    Project "/Users/nrudnyk/Downloads/TestProjectAndBindingLib/TestProjectBindingLib/TestProjectConsumer/TestProjectConsumer.csproj" is building "/Users/nrudnyk/Downloads/TestProjectAndBindingLib/TestProjectBindingLib/TestProjectBindingLib/TestProjectBindingLib.csproj" (GetNativeManifest target(s)):

Target GenerateTargetFrameworkMonikerAttribute:
  Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the input files.
Target CoreCompile:
  Skipping target "CoreCompile" because all output files are up-to-date with respect to the input files.
Target _CopyFilesMarkedCopyLocal:
    Touching "/Users/nrudnyk/Downloads/TestProjectAndBindingLib/TestProjectBindingLib/TestProjectConsumer/obj/iPhone/Debug/TestProjectConsumer.csproj.CopyComplete".
Target GetCopyToOutputDirectoryItems:
    Target _GetCopyToOutputDirectoryItemsFromTransitiveProjectReferences:
        __________________________________________________
        Project "/Users/nrudnyk/Downloads/TestProjectAndBindingLib/TestProjectBindingLib/TestProjectConsumer/TestProjectConsumer.csproj" is building "/Users/nrudnyk/Downloads/TestProjectAndBindingLib/TestProjectBindingLib/TestProjectBindingLib/TestProjectBindingLib.csproj" (GetCopyToOutputDirectoryItems target(s)):

Target CopyFilesToOutputDirectory:
    TestProjectConsumer -> /Users/nrudnyk/Downloads/TestProjectAndBindingLib/TestProjectBindingLib/TestProjectConsumer/bin/iPhone/Debug/TestProjectConsumer.exe
Target _DetectSigningIdentity:
    Detected signing identity:
      Code Signing Key: "Apple Development: Nazar Rudnyk (A466QN3HLS)" (B5ED1E24A0A5D546161170215274D5DA2AE2C48C)
      Provisioning Profile: "iOS Team Provisioning Profile: *" (37edf304-158d-44d0-b2dd-1aff4050119e)
      Bundle Id: test.testprojectconsumer
      App Id: 4RZQG425FX.test.testprojectconsumer
Target _CopyResourcesToBundle:
  Skipping target "_CopyResourcesToBundle" because all output files are up-to-date with respect to the input files.
Target _DetectDebugNetworkConfiguration:
      DebugIPAddresses: 
Target _CompileAppManifest:
  Skipping target "_CompileAppManifest" because all output files are up-to-date with respect to the input files.
Target _ParseExtraMtouchArgs:
      NoSymbolStrip Output: true
      NoDSymUtil Output: false
Target _CompileToNative:
  Skipping target "_CompileToNative" because all output files are up-to-date with respect to the input files.
Target _CompileITunesMetadata:
  Skipping target "_CompileITunesMetadata" because all output files are up-to-date with respect to the input files.
Target _CopyITunesArtwork:
  Skipping target "_CopyITunesArtwork" because it has no inputs.
Target _CopyAppExtensionsToBundle:
  Skipping target "_CopyAppExtensionsToBundle" because it has no inputs.
Target _GenerateAppExtensionDebugSymbols:
    Directory "bin/iPhone/Debug/device-builds/iphone10.6-13.3.1/TestProjectConsumer.app/../.dSYM" doesn't exist. Skipping.
Target _GenerateFrameworkDebugSymbols:
  Skipping target "_GenerateFrameworkDebugSymbols" because all output files are up-to-date with respect to the input files.
Target _GenerateDebugSymbols:
  Skipping target "_GenerateDebugSymbols" because all output files are up-to-date with respect to the input files.
Target _CodesignFrameworks:
  Skipping target "_CodesignFrameworks" because all output files are up-to-date with respect to the input files.
Target _CodesignAppBundle:
  Skipping target "_CodesignAppBundle" because all output files are up-to-date with respect to the input files.
Target _CodesignVerify:
    /usr/bin/codesign --verify -vvvv -R='anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.1] exists and (certificate leaf[field.1.2.840.113635.100.6.1.2] exists or certificate leaf[field.1.2.840.113635.100.6.1.4] exists)' bin/iPhone/Debug/device-builds/iphone10.6-13.3.1/TestProjectConsumer.app 
    bin/iPhone/Debug/device-builds/iphone10.6-13.3.1/TestProjectConsumer.app: valid on disk
    bin/iPhone/Debug/device-builds/iphone10.6-13.3.1/TestProjectConsumer.app: satisfies its Designated Requirement
    bin/iPhone/Debug/device-builds/iphone10.6-13.3.1/TestProjectConsumer.app: explicit requirement satisfied

Build succeeded.

/Library/Frameworks/Mono.framework/Versions/6.8.0/lib/mono/msbuild/Current/bin/Microsoft.Common.CurrentVersion.targets(3276,5): warning MSB9004: ManifestResourceWithNoCulture item type is deprecated. Emit EmbeddedResource items instead, with metadata WithCulture='false', Type='Resx', and optional LogicalName.
    1 Warning(s)
    0 Error(s)

Time Elapsed 00:00:01.14

========== Build: 2 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Build: 0 errors, 1 warning

Example Project (If Possible)

For the sake of simplicity, test project is simple view controller which push another one, with Native object inside it. This makes possible going back\forth to clearly see the leak.

TestProjectAndBindingLib.zip

I might miss something, if so - please let me know, any suggestions is greatly appreciated.
Thank you in advance!

@chamons
Copy link
Contributor

chamons commented Apr 8, 2020

How are you measure memory usage / leaks?

Are you waiting on the garbage collector to collect the managed instances, or are you just hitting the button over and measuring?

Unlike ObjC, C# uses a garbage collector so memory isn't immediately freed when popping a controller.

@chamons chamons added need-info Waiting for more information before the bug can be investigated question The issue is a question labels Apr 8, 2020
@chamons chamons added this to the Future milestone Apr 8, 2020
@nrudnyk
Copy link
Author

nrudnyk commented Apr 8, 2020

sure, I'm aware about GC, and guess it I was forcing collection on each controller pop (going back to the main view). It's not included in the test project, since it doesn't make any change.

To answer your question - using memory graph as well as instruments, which shows memory spikes, there's a screenshots attached in the OP

@chamons
Copy link
Contributor

chamons commented Apr 8, 2020

It is very helpful, in particular on tricky issues like "memory leaks", where false positives are exceptionally easy to find, for the sample to accurately show how you are measuring things.

Can you please attach a sample with whatever memory management techniques you use to handle garbage collection and collect your number?

For every actual reported memory leak I see 5 where people misunderstand what they are measuring, GCs make things less obvious than one would first expect.

@nrudnyk
Copy link
Author

nrudnyk commented Apr 9, 2020

Hello Chris,

The problem isn't in the garbage collection, the issue is that it works fine If no methods were overridden, and doesn't it there some. There's no fancy techniques to be used in this simple project, everything is disposed, events' are unsubscribed etc... this test project contains only 2 view controllers and native class with overridden method, and that's only to be able to showcase increasing memory...

I'm trying to think simple here, there are 2 cases for the native class used:

  1. no overrides
  2. there is an override for some of it's methods

First one, works with no problems, and second causes increasing of memory usage each time.

I understand, that there are a lot of false positive reports, and that's why prepared simple project right in the OP, so you can just "click and run" it, and see the problem i'm talking about. I'm not saying that's there is a bug or an issue in Xamarin.iOS, but there's something going on related to binding's generator and overrides. Also, Ш'm not omit the fact, that I might miss something, but the project is very very simple, so it's either I'm doing something wrong, or there's the issue in "under the hood" code. Hence - asking here.

But anyways, since you asking how I measure, I decided to slim the project, and include GC code. You can find it below:
Slim-Test-Project.zip

In this example, there's only appDelegate, with simple code (2 cases)

  1. One uses object with overriden method
  2. Other don't use it.

Since c# collector doesn't know about native object, and only know about references, I used XCode to check memory. So here's what I did for each case:

  • put breakpoint on before GCTest() is called
  • attach Xcode to the Xamarin.iOS process
  • open memory graph
  • go through that calls one by one (there's 3 of them)
    See the results for cases below:

Case with override:
Screenshot 2020-04-09 at 11 13 20
Case without override:
Screenshot 2020-04-09 at 11 16 40

In addition, you can find data from the GC.GetTotalMemory(false) in console, which looks strange, because for some reason c# memory is increasing after GC.Collect()

Hope that helps and you might be able to bring some insights about what's wrong with this example.

Thanks in advance!

@nrudnyk
Copy link
Author

nrudnyk commented Apr 16, 2020

@chamons is there anything else I can do, so you can let me know what am I missing here?

@chamons chamons removed the need-info Waiting for more information before the bug can be investigated label Apr 17, 2020
@chamons chamons self-assigned this Apr 17, 2020
@chamons
Copy link
Contributor

chamons commented Apr 17, 2020

Taking a look into this is on my backlog plate, we've just been a bit swamped.

@nrudnyk
Copy link
Author

nrudnyk commented Jun 22, 2020

@chamons hello. Did you have a chance to look into this?

@chamons
Copy link
Contributor

chamons commented Jun 22, 2020

No, I was not able to make much progress on it recently. Given the soon release of Xcode 12 Beta it may be awhile.

Apologies.

@nrudnyk
Copy link
Author

nrudnyk commented Jun 22, 2020

maybe there's some timetable or deadline, so we are aware of what to expect...?

@chamons
Copy link
Contributor

chamons commented Jun 23, 2020

While many problems can be resolved over github issues given sufficient time, they are prioritized based upon broad customer impact.

Because of this, it is not possible to lay out a timetable or deadline on when we'll be able to get back to looking on this, specially with Xcode 12 work beginning this summer.

If you are eligible for business supports requests with Microsoft, you can consider submitting a support request to the Xamarin support team.

@andyb1979
Copy link

+1 for this issue. It's affecting our customers at SciChart - a fast iOS and Xamarin realtime chart control.

If we get customer issues reporting can we point them here to log / vote for the issue?

@nrudnyk
Copy link
Author

nrudnyk commented Sep 29, 2020

hello @chamons, since XCode 12 is released already, maybe there's a time to look into this issue?

@nrudnyk
Copy link
Author

nrudnyk commented Jan 12, 2021

any updates with regards to this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question The issue is a question
Projects
None yet
Development

No branches or pull requests

3 participants