Compact Framework Memory Management

Download Report

Transcript Compact Framework Memory Management

Compact Framework Memory Management

Chris Tacke Principal Partner OpenNETCF Consulting www.OpenNETCF.com

Introduction

Microsoft Windows CE memory architecture Windows CE application memory usage GC heap How it grows and shrinks JIT Heap How it grows and shrinks Demo - Remote Performance Monitor (RPM) Managed application costs Managed code and deterministic behavior

RAM DLLs load at the top of the slot Code loads at the bottom App data and resources load above code Stack and heaps load in reserved space above resources Remainder is free virtual space for process In-ROM DLLs are in Slot1 (XIP) Other processes are paged in

RAM DLLs Virtual Space Stack/heap Data Code Shared memory 0x8000 0000 0x0400 0000 0x0200 0000 0x0000 0000 Other Slots 2-31 processes

Executing a Managed Application

The typical managed developer’s view My application Loads some references Uses the Microsoft .NET Compact Framework Calls some arcane “Native stuff”

Application Managed references Compact framework Native stuff

A Deeper Look

1. CLR loads 2. App and class library assemblies load 3. EE JIT compiles code 4. Reference types allocated from GC Heap 5. Types generated in memory from metadata 6. Miscellaneous allocations

Application Managed references Compact framework Native stuff MyReference.dll

0x8000 0000

Shared memory Metadata Slots 2-31

0x0400 0000

Slot 1

0x0200 0000 0x0000 0000

Slot 0 GC Heap AppDomain Heap

GC heap holds allocations for reference types in 64K segments Allocations in a segment are fast because they are simple pointer arithmetic Eventually an allocation will require more memory than the heap contains 64+K Segment If more memory is not available, OOM Exception is thrown Another segment is added to the Heap through a VirtualAlloc call and allocation continues. NOTE: Segments are not necessarily contiguous memory.

If an object requires > 64K allocation, a segment large enough is created for the allocation (not necessarily a 64K multiple) 64+K Segment ptr

Object H Object G Object F Object E Object E Object D Object C Object B Object A

GC Resource Recovery

Resources are recovered through a process called “collection” A collection is triggered by specific conditions For every 1 MB of heap data allocated (not tied directly to heap size) An OOM on most large allocations (bitmaps, etc.) The application receives a WM_HIBERNATE message The application moves to the background The application explicitly calls GC.Collect

GC Collection Activities

A collection will

always

: Free unreferenced objects in the heap that have no finalizer or whose finalizer has already run A Collection

may

: Compact the GC heap (combine small free spaces by moving objects) Shrink the GC heap itself Release (pitch) JITted code The application explicitly calls GC.Collect

To fully understand GC resource recovery, we need a deeper understanding of allocation

GC Internals

Strong references to objects are called “roots” and are maintained by the CLR When new objects are created, a reference is stored as a root If an object has a Finalize method, a reference to it is also added to the finalization queue As objects are destroyed or go out of scope, roots are removed During collection the GC walks all roots, marking all actively referenced objects in the heap (mark) After marking all objects from roots, unmarked objects are released (sweep)

Finalization queue Object E Roots Strong references Globals Statics Locals Object E (Has Finalize) Object D (No Finalize) Object C Object B Object A

GC Internals

When a finalizable object is destroyed root reference is removed as usual During GC Collection objects in finalization queue are not released Instead, a reference is added to a special root called the freachable queue and the finalization queue entry is removed Once collection is complete, a separate thread runs Finalize on all items in the freachable queue Once Finalize has been run, the freachable reference is removed On the next collection the object memory will be released

Finalization queue Object E Finalizer thread Roots Freachable queue Object E (Has finalize) Object C Object A

After Collection

After a collection cycle, allocations begin again from the beginning of the heap. An allocation is made in the first “hole” into which it will fit Allocation pointer moves to the beginning of the first segment Segments hold a pointer to first available hole so locating it is still fast Allocator will attempt to fill holes with subsequent allocations. The pointer will continue to move up until either a large enough hole is found or we reach the top of the GC heap and new memory must be allocated Same process happens with “active” segement before new segments are created ptr

Object H

ptr

Object X

ptr

Object C

ptr ptr

Object A

GC Heap Compaction

When the GC heap has 750k or more of free space (holes) during collection, a compaction occurs Note that the GC heap does not necessary shrink when this occurs If the GC heap exceeds 1MB in size, segments will be released down to the 1MB line if they are empty

0x0010 0000 Object H Object H 0x0000 0000 Object C Object C Object A

JIT Compiler

Has its own heap separate from the GC heap Does not highly optimize during compiling Speed of compile chosen over code density or execution speed Roughly 50% as “good” as the FFx compiler or a typical native C++ compiler Optimized for short code paths Method calls are 2-5 times slower than in the FFx or native code Avoid recursion and heavy use of abstraction layers

JIT Heap Growth (JIT Compiling)

IL is compiled per method and on the fly Small increments Assembly is 2-3 times the size of the source IL JIT Heap growth is unbounded if .Net Compact Framework 2.0

JIT Heap Shrinkage (Code Pitching)

Shrinks by almost all code Unlike growth, shrinking is not incremental Compiler keeps only JITted code for current call stack Triggers Memory allocation failure WM_HIBERNATE message received Application is sent to the background

Remote Performance Monitor (RPM)

The Fixed Costs of Managed Code

.NET CF 2.0 takes ~2.2 MB in ROM (compressed) CLR native components require 650K virtual space, max of 650K physical Slot 1 if in ROM, Slot 0 if installed in the field .NET CF-managed assemblies take 3.8 MB of shared virtual space plus 1-2 MB of physical space from the 32 MB process slot This is a one-time cost per device (shared across all managed applications)

The Fixed Costs of Managed Code

Applications allocate out of the 1 GB shared slot as memory-mapped files Applications are compressed and will grow in virtual size ~50% when mapped Required physical memory is demand paged in (probably ~50% of virtual size required to prevent thrashing)

The Dynamic Costs of Managed Code

CLR data structures require <250K JIT Heap typically 250K-500K from the 32 MB process space Long code paths create requirements to hold more JITted code at one time. Even without the perf hit for method calls this can be a problem Almost all JITted code is pitched when app is in the background GC heap size is unbounded Comes from the 32 MB process space

The Dynamic Costs of Managed Code

Each thread gets a 64K stack Allocated from 32 MB process space Not freed until the thread is collected

“Controlling” the GC

Rule 1: The GC cannot be directly controlled except by calling GC.Collect

When you call GC.Collect the GC must: 1.

2.

3.

4.

5.

Suspend all threads in the process Traverse all roots Mark all objects with a referring root Traverse all objects in the GC heap to see if they’re marked Traverse the finalizer queue

“Controlling” the GC

Any GC.Collect() call is inherently expensive and it’s extremely rare that an application should ever call it Since finalizers are run on a separate thread, it is not guaranteed, and is actually unlikely, that Finalize method execution will be done when the call to GC.Collect returns Deterministic finalization is not possible Never assume finalization if you manually call collect

“Real Time” and Determinism

The inherent problem with managed environments What exactly is “real time”?

“Real time” is defined as a system with deterministic results. This means that you can guarantee that when an action occurs, the time for the reaction has an defined upper bound.

Example: An interrupt occurs, the handler must run within some bounded time frame or bad things happen (system failure, damaged product, injury, etc)

“Real Time” and Determinism

The inherent problem with managed environments By their very nature, all garbage-collected systems (FFx, .NET CF, Java, etc.) are inherently nondeterministic GC can run at any time Time required to collect is indeterminate GC suspends all other threads during collection Reminder: Since finalizers are run on a separate thread it is not guaranteed, and is actually unlikely, that finalizers will be done when GC.Collect returns. This means deterministic finalization is not possible

Determinism in the Managed Environment

Achieving the impossible Requires exhaustive testing and a thorough understanding of the entire system, not just your application. Not recommended fault tolerant systems.

for critical or non-

Determinism in the Managed Environment

Achieving the impossible To get deterministic behavior we must: Identify what parts of our code need determinism Determinism of entire app is not achievable Protect those parts from the effects of GC Collection Remember my Three Rules of Managed Determinism

The Three Rules of Managed Determinism

1.

2.

3.

Collection occurs when certain known trigger events occur (i.e. OOM, 1 MB allocation, etc.) Collection runs on the current thread, not its own thread Thread behavior is “adjustable” at the API level

Determinism in the Managed Environment

Step 1: Handle GC triggers Allocation-based triggers (e.g. OOM or 1MB GC heap threshold) Never, ever (ever) make an allocation in your real time code Beware of boxing (allocations made on your behalf)

Determinism in the Managed Environment

Step 1: Handle GC triggers WM_HIBERNATE event It’s your system, do your best to know what else is running Open systems are far more fragile than closed systems Intercept WM_HIBERNATE with your own message pump (e.g. IMessageFilter implementation)

Determinism in the Managed Environment

Step 1: Handle GC triggers Application moving to the background Disallow it during execution of real time code sections Use Mutexes, Critical sections, etc

Determinism in the Managed Environment

Step 1: Handle GC triggers Direct calls to GC.Collect

Even if you’re tempted, just don’t do it

Determinism in the Managed Environment

Step 2: Protect yourself Take advantage of Rules 1 and 2. Since GC runs on the current thread and thread behavior is API adjustable.

Put your real-time code in a separate thread Assuming we’ve handled step 1 and make no allocations, GC will always run in the non-real time thread Raise your real time thread’s priority (above normal application priorities) via CeSetThreadPriority Set your real time thread’s quantum to “run to completion” via CeSetThreadQuantum Keep your real-time thread to a minimum to avoid system impact

Sample Real Time IST

private void LaunchStartup() { Thread2 ist = new Thread2(ISTProc); // set IST priority well above app priority ist.RealTimePriority = 200; // run to completion ist.RealTimeQuantum = 0; ist.Start(); }

Sample Real Time IST

private void ISTProc() { EventWaitHandle interruptWaitHandle = new EventWaitHandle( false, EventResetMode.AutoReset, "ISR_EVENT_NAME"); // allocate any variables here, outside the IST loop while(true) { interruptWaitHandle.WaitOne(); // handle the interrupt here // do *NOT* allocate any variables } }

Questions?

Newsgroups microsoft.public.dotnet.framework.compactframework

Blogs http://blog.opennetcf.org

http://blogs.msdn.com/netcfteam Slide deck is on CommNet Code will be posted in my blog Chris Tacke OpenNETCF Consulting www.OpenNETCF.com

[email protected]

Resources

Need developer resources on this subject? Stop by the MED Content Publishing Team Station in the Microsoft Pavilion or visit the MED Content Publishing Team Wiki site: http://msdn.microsoft.com/mobility/wiki

© 2006 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.

The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.