3

I have an application which operates with memory a lot. This app written in c# - it has mono runtime under the hood.

We identfied that on Sierra the app memory constantly grows when it does consuming memory operations. Same time the issue is not reproducible on El Captain.

It can even achive 8 or 10 GB if it works a long period of time (weeks).

enter image description here

I have verified that there is no memory leaks (significant, which can cause such a growth). I have verified that there is no retain cycles preventing objects from being collected - again the app works perfect on El Captain.

I found that:

  • Almost all app memory (excluding 150 mb of active) moves to compressed state and even swaped to disk then.

  • According to Xcode Instruments VM Tracker tool - VM_Allocation region holds almost all swapped memory

    <---!!! - pay attention to

    % of Res.   Type    # Regs  Path            Resident Size   Dirty Size  Swapped Size        Virtual Size    Res. %  
    100%        *All*   17997   < multiple >    517.21 MiB      240.89 MiB  704.31 MiB <---!!!  2.07 GiB        24% 
    
    % of Res.   Type        # Regs      Path    Resident Size   Dirty Size  Swapped Size        Virtual Size    Res. %  
    18%         VM_ALLOCATE 15939       -       90.76 MiB       90.76 MiB   588.81 MiB <---!!!  696.29 MiB      13% 
    

I dtrace-ed all occurences and stack traces of virtual memory allocation/ deallocations - mmap(), munmap(), vm_allocate(), vm_deallocate() and found that:

For each mmap() of currently swapped memory pages there was corresponding successfull munmap() For each vm_allocate() of currently swapped memory pages there was corresponding successfull vm_deallocate()

but

for some reason munmap() of some vm region returns "0" which means success but associated pages are still presented - they are not returned to system.

That's not expected - munmap() of private, ananymous memory should lead to page freeing. I verified that in my sample app. Any manipulations with mlock(), madvice() did not help to imitate this.

That causes an issues as that pages are abandoned by GC (they are not reused anymore) same time they are not free. As they are no longer in use they go thru compressing and then swapping to disk.

Moreover, abandoned pages are alive - access to them from lldb does not lead to BAD_ACCESS.

Has anyone met this?

Here are extractions from the logs which show the problem.

   This is VM state evolution in 0x11c5XXXXX range of 1 MB:

   I. allocation, deallocation object in Large objects space

   Type Address Range   Dirty Size  Swapped Size    Resident Size   Virtual Size    Resident %  Protections Path
   VM_ALLOCATE  0x11c500000 - 0x11c600000   1.00 MiB    0 Bytes 1.00 MiB    1.00 MiB    100%    rw-/rwx 

     3    551                      mmap:return [240760570406181]:mmap:  [0x11c500000, 2097152] flags: 4098
                 libsystem_kernel.dylib`__mmap+0xa
                 Drive`mono_valloc+0x69
                 Drive`mono_valloc_aligned+0x22
                 Drive`sgen_alloc_os_memory_aligned+0x23
                 Drive`sgen_los_alloc_large_inner+0x274
                 Drive`sgen_alloc_obj_nolock+0x69
                 Drive`mono_gc_alloc_vector+0x7b
                 0x1063cb0e6
                 0x117429a4a
                 0x1174296d2
                 0x11742881c
                 0x1174286ca
                 0x117428530
                 0x1173a77cd
                 0x11739a81a
                 0x11739a2e1
                 0x11739a213
                 0x116ad373b
                 0x111a2f199
                 0x10df54fc9

     3    303                    munmap:return [240983284059591]:munmap: 0   0x11c500000, 1048576
                 libsystem_kernel.dylib`__munmap+0xa
                 Drive`mono_valloc_aligned+0xd0
                 Drive`sgen_alloc_os_memory_aligned+0x23
                 Drive`sgen_los_alloc_large_inner+0x274
                 Drive`sgen_alloc_obj_nolock+0x69
                 Drive`mono_gc_alloc_vector+0x7b
                 0x1063cb0e6
                 0x117429a4a
                 0x1174296d2
                 0x11742881c
                 0x1174286ca
                 0x117428530
                 0x1173a77cd
                 0x11739a81a
                 0x11739a2e1
                 0x11739a213
                 0x116ad373b
                 0x111a2f199
                 0x10df54fc9
                 Drive`mono_jit_runtime_invoke+0x8e0

   II. SQLITE page cache allocation / deallocation 

   Type Address Range   Dirty Size  Swapped Size    Resident Size   Virtual Size    Resident %  Protections Path
   SQLite page cache    0x11c50f000 - 0x11c51f000   64.00 KiB   0 Bytes 64.00 KiB   64.00 KiB   100%    rw-/rwx 
   SQLite page cache    0x11c51f000 - 0x11c52f000   64.00 KiB   0 Bytes 64.00 KiB   64.00 KiB   100%    rw-/rwx 

   [241059759675635]:vm_allocate:   0x11c50f000, 0x10000

                 libsystem_kernel.dylib`vm_allocate+0x26
                 libsqlite3.dylib`purgeableCacheFetch+0x32a
                 libsqlite3.dylib`sqlite3PagerGet+0x18d
                 libsqlite3.dylib`getAndInitPage+0x47
                 libsqlite3.dylib`sqlite3BtreeMovetoUnpacked+0x52d
                 libsqlite3.dylib`handleDeferredMoveto+0x1e
                 libsqlite3.dylib`sqlite3VdbeExec+0x9b72
                 libsqlite3.dylib`sqlite3_step+0x3cf
                 0x11188e240

   [241097285460026]:vm_deallocate: 0x11c50f000

                 libsystem_kernel.dylib`vm_deallocate
                 libsqlite3.dylib`purgeableCacheDestroy+0x464
                 libsqlite3.dylib`sqlite3PagerClose+0x279
                 libsqlite3.dylib`sqlite3BtreeClose+0x142
                 libsqlite3.dylib`sqlite3LeaveMutexAndCloseZombie+0x192
                 libsqlite3.dylib`sqlite3Close+0x409
                 0x112caf100
                 0x112caee8d
                 0x11188ec28
                 0x112fee6d5
                 Drive`mono_gc_run_finalize+0x3fc
                 Drive`sgen_gc_invoke_finalizers+0x114
                 Drive`finalizer_thread+0x252
                 Drive`start_wrapper+0x22e
                 Drive`inner_start_thread+0x196
                 libsystem_pthread.dylib`_pthread_body+0xb4
                 libsystem_pthread.dylib`_pthread_body
                 libsystem_pthread.dylib`thread_start+0xd


   III. SQLITE page cache deallocation. These three guys are unknown... That's strange - my assumption that the reason that I don't have allocation stack trace for them is dtrace failure - it reports errors a little from time to time

   Type Address Range   Dirty Size  Swapped Size    Resident Size   Virtual Size    Resident %  Protections Path
   VM_ALLOCATE  0x11c5ef000 - 0x11c5f1000   8.00 KiB    0 Bytes 8.00 KiB    8.00 KiB    100%    rw-/rwx 
   VM_ALLOCATE  0x11c5f1000 - 0x11c5f2000   4.00 KiB    0 Bytes 4.00 KiB    4.00 KiB    100%    rw-/rwx 
   VM_ALLOCATE  0x11c5f5000 - 0x11c5fa000   20.00 KiB   0 Bytes 20.00 KiB   20.00 KiB   100%    rw-/rwx 


   IV. FIRST REPRODUCTION <---!!! 0x11c51e000 - mmapped() then munmapped() but still be presented.
   Type Address Range   Dirty Size  Swapped Size    Resident Size   Virtual Size    Resident %  Protections Path
   SQLite page cache    0x11c50e000 - 0x11c51e000   0 Bytes 0 Bytes 0 Bytes 64.00 KiB   0%  rw-/rwx 
   VM_ALLOCATE  0x11c51e000 - 0x11c529000   44.00 KiB   0 Bytes 44.00 KiB   44.00 KiB   100%    rw-/rwx 
   VM_ALLOCATE  0x11c5ef000 - 0x11c5f1000   8.00 KiB    0 Bytes 8.00 KiB    8.00 KiB    100%    rw-/rwx 
   VM_ALLOCATE  0x11c5f1000 - 0x11c5f2000   4.00 KiB    0 Bytes 4.00 KiB    4.00 KiB    100%    rw-/rwx 
   VM_ALLOCATE  0x11c5f5000 - 0x11c5fa000   20.00 KiB   0 Bytes 20.00 KiB   20.00 KiB   100%    rw-/rwx 


   0    551                      mmap:return [241237210309703]:mmap:   [0x11c51e000, 4096] flags: 4098
                 libsystem_kernel.dylib`__mmap+0xa
                 Drive`mono_valloc+0x69
                 Drive`mono_lock_free_alloc+0x335
                 Drive`sgen_alloc_internal+0x3b
                 Drive`sgen_gray_object_enqueue+0x5c
                 Drive`mono_g_hash_mark+0x11a
                 Drive`job_scan_from_registered_roots+0x18c
                 Drive`sgen_workers_enqueue_job+0x23
                 Drive`enqueue_scan_from_roots_jobs+0x7d
                 Drive`major_copy_or_mark_from_roots+0x36a
                 Drive`major_start_collection+0x155
                 Drive`major_do_collection+0x4e
                 Drive`sgen_perform_collection+0x2a6
                 Drive`sgen_los_alloc_large_inner+0x5d
                 Drive`sgen_alloc_obj_nolock+0x69
                 Drive`mono_gc_alloc_vector+0x7b
                 0x1063cb0e6
                 0x10bd2a7b3
                 0x10bd293d1
                 0x1173a6db6



     2    303                    munmap:return [241257343803100]:munmap: 0    <---!!!    0x11c51e000, 4096
                 libsystem_kernel.dylib`__munmap+0xa
                 Drive`mono_vfree+0x32
                 Drive`desc_retire+0x43
                 Drive`mono_lock_free_free+0x1a9
                 Drive`pin_stats_tree_free+0x20
                 Drive`pin_stats_tree_free+0x20
                 Drive`pin_stats_tree_free+0x17
                 Drive`pin_stats_tree_free+0x17
                 Drive`pin_stats_tree_free+0x20
                 Drive`pin_stats_tree_free+0x17
                 Drive`pin_stats_tree_free+0x17
                 Drive`pin_stats_tree_free+0x20
                 Drive`pin_stats_tree_free+0x20
                 Drive`pin_stats_tree_free+0x20
                 Drive`pin_stats_tree_free+0x20
                 Drive`pin_stats_tree_free+0x20
                 Drive`pin_stats_tree_free+0x20
                 Drive`sgen_pin_stats_reset+0x10
                 Drive`collect_nursery+0x414
                 Drive`sgen_perform_collection+0x1b1


   V. Done - all the memory in the range is abandoned

   Type Address Range   Dirty Size  Swapped Size    Resident Size   Virtual Size    Resident %  Protections Path
   VM_ALLOCATE  0x11c51c000 - 0x11c51e000   0 Bytes 8.00 KiB    0 Bytes 8.00 KiB    0%  rw-/rwx 
   VM_ALLOCATE  0x11c51e000 - 0x11c53c000   0 Bytes 120.00 KiB  0 Bytes 120.00 KiB  0%  rw-/rwx 
   VM_ALLOCATE  0x11c53c000 - 0x11c550000   0 Bytes 80.00 KiB   0 Bytes 80.00 KiB   0%  rw-/rwx 
   VM_ALLOCATE  0x11c550000 - 0x11c568000   0 Bytes 96.00 KiB   0 Bytes 96.00 KiB   0%  rw-/rwx 
   VM_ALLOCATE  0x11c568000 - 0x11c569000   0 Bytes 4.00 KiB    0 Bytes 4.00 KiB    0%  rw-/rwx 
   VM_ALLOCATE  0x11c569000 - 0x11c57d000   0 Bytes 80.00 KiB   0 Bytes 80.00 KiB   0%  rw-/rwx 
   VM_ALLOCATE  0x11c57d000 - 0x11c589000   0 Bytes 48.00 KiB   0 Bytes 48.00 KiB   0%  rw-/rwx 
   VM_ALLOCATE  0x11c589000 - 0x11c58b000   0 Bytes 8.00 KiB    0 Bytes 8.00 KiB    0%  rw-/rwx 
   VM_ALLOCATE  0x11c58b000 - 0x11c58c000   0 Bytes 4.00 KiB    0 Bytes 4.00 KiB    0%  rw-/rwx 
   VM_ALLOCATE  0x11c58c000 - 0x11c594000   0 Bytes 32.00 KiB   0 Bytes 32.00 KiB   0%  rw-/rwx 
   VM_ALLOCATE  0x11c594000 - 0x11c5b3000   0 Bytes 124.00 KiB  0 Bytes 124.00 KiB  0%  rw-/rwx 
   VM_ALLOCATE  0x11c5b3000 - 0x11c5b5000   0 Bytes 8.00 KiB    0 Bytes 8.00 KiB    0%  rw-/rwx 
   VM_ALLOCATE  0x11c5b5000 - 0x11c5c9000   0 Bytes 80.00 KiB   0 Bytes 80.00 KiB   0%  rw-/rwx 
   VM_ALLOCATE  0x11c5c9000 - 0x11c5cd000   0 Bytes 16.00 KiB   0 Bytes 16.00 KiB   0%  rw-/rwx 
   VM_ALLOCATE  0x11c5cd000 - 0x11c5d1000   0 Bytes 16.00 KiB   0 Bytes 16.00 KiB   0%  rw-/rwx 
   VM_ALLOCATE  0x11c5d1000 - 0x11c5df000   0 Bytes 56.00 KiB   0 Bytes 56.00 KiB   0%  rw-/rwx 
   VM_ALLOCATE  0x11c5df000 - 0x11c5ee000   0 Bytes 60.00 KiB   0 Bytes 60.00 KiB   0%  rw-/rwx 
   VM_ALLOCATE  0x11c5ee000 - 0x11c5ef000   0 Bytes 4.00 KiB    0 Bytes 4.00 KiB    0%  rw-/rwx 
   VM_ALLOCATE  0x11c5ef000 - 0x11c5f1000   0 Bytes 8.00 KiB    0 Bytes 8.00 KiB    0%  rw-/rwx 
   VM_ALLOCATE  0x11c5f1000 - 0x11c5f5000   0 Bytes 16.00 KiB   0 Bytes 16.00 KiB   0%  rw-/rwx 
   VM_ALLOCATE  0x11c5f5000 - 0x11c5fa000   0 Bytes 20.00 KiB   0 Bytes 20.00 KiB   0%  rw-/rwx 
   VM_ALLOCATE  0x11c5fa000 - 0x11c619000   0 Bytes 124.00 KiB  0 Bytes 124.00 KiB  0%  rw-/rwx 
jgoldberger - MSFT
  • 5,978
  • 2
  • 20
  • 44
Igor B.
  • 2,219
  • 13
  • 17

0 Answers0