Memory usage increases with each image

6 posts, 1 answers
  1. John
    John avatar
    6 posts
    Member since:
    Oct 2011

    Posted 19 Mar 2012 Link to this post

    I am using the Windows Phone Slide View control to browse albums of images.

    Open page bind to a list of images, close page.  Open (same) page, bind to (different) list of images.
    If user has say 5 or 6 albums... this would go over the 90MB requirement for Windows phone certification.
    The  memory seems to be stacking up (adding to it's previous high each time).

    Is this normal? I would think that the Slide Viewer would release the memory once you exit the page.

    OR is this not even the slide view's fault, is WindowsPhone itself caching the images in memory and counting it against my app memory usage?  I would certainly like to try and keep image viewing available for the 256MB phones (and upcoming tango Memory limitations).

    5.2.5 Memory Consumption

    An application must not exceed 90 MB of RAM usage, except on devices that have more than 256 MB of memory.

    You can use the following classes to query the amount of memory that is available on the device and modify the application behavior at runtime to take advantage of additional memory:

    The DeviceTotalMemory value indicates the physical RAM size in bytes. This value is less than the actual amount of device memory. For an application to pass certification, Microsoft recommends that the value returned by ApplicationPeakMemoryUsage is less than 90 MB when DeviceTotalMemory is less than or equal to 256 MB.


    My Code...
    <telerik:RadSlideView x:Name="slideView" Grid.Row="2" IsLoopingEnabled="False"   ItemsSource="{Binding Thumbs}">
                <telerik:RadSlideView.ItemTemplate>
                    <DataTemplate>
                            <ScrollViewer>
                                <StackPanel>                                
                                    <Image Source="{Binding PreviewURL}"  MaxWidth="480" MaxHeight="500"  />
                                    <TextBlock Text="{Binding Caption}"   />
                                </StackPanel>
                            </ScrollViewer>
                    </DataTemplate>
                </telerik:RadSlideView.ItemTemplate>
            </telerik:RadSlideView>





  2. John
    John avatar
    6 posts
    Member since:
    Oct 2011

    Posted 19 Mar 2012 Link to this post

    I'm not sure this is the fault of the slide view... i notice this happening on every single page click I do not matter how small...
    cant quite figuer it out but it does not appear to be the fault of the Slide Viewer... (still researching).  

    It just is more visible becuase the slide viewer is dealing with bigger items ( images ) so it's more apparent.
  3. DevCraft banner
  4. Kiril Stanoev
    Admin
    Kiril Stanoev avatar
    1511 posts

    Posted 21 Mar 2012 Link to this post

    Hello John,

    Thank you for contacting us. Unfortunately I was not able to reproduce the issue as well. I've created a sample project according to your specification, but the memory consumption barely went over 50 MB. Could you please take a look at the attached project and let me know if I am missing anything. I'd be glad to further assist you.

    Regards,
    Kiril Stanoev
    the Telerik team
    Sharpen your .NET Ninja skills! Attend Q1 webinar week and get a chance to win a license! Book your seat now >>
  5. Answer
    John
    John avatar
    6 posts
    Member since:
    Oct 2011

    Posted 21 Mar 2012 Link to this post

    I have been doing much research the last day or two and have found out a lot.
    The scope of the discussion goes beyond the slide view ... below:


    For windows phone if you do not release things explicitly, the entire visual tree from that point on is subject (some elements yes, some elements no) to get stuck in memory.  Multiple calls to the same page will stack up the memory till it goes over 90MB.  It will also start stacking if one starts accessing different pages with the same issue of not releasing memory.  

    The reason I first thought it was the slide view's fault is because that was my heaviest page ( with images ) and it surfaced the problem sooner.

    To isolate this issue I created a new project with two static pages.. one with a hyperlink to another and the other with nothing but text blocks.  Even with 10 simple text blocks i was able to see the memory stack.    Once the memory hits 40MB and 70MB there is quite a bit of resistance because the Garbage Collector starts getting called at this point. I was surprised to read that the GC doesn't really get called all the time.    So I expanded the text blocks to flush out the issue further to something like 200 or 300 text blocks.  This will definitely push over the 90MB. There will be resistance at the 40MB and 70MB levels and most people will stop clicking but for some reason if you keep clicking it will eventually go over those thresholds and keep stacking the memory.  And that is with static text blocks.  

    Text Blocks Solution
    what was the solution that worked for me ( both text blocks example, and my RadSlideView project).
    So my answer for the Text Blocks was simple.  Overriding the OnNavigatedTo method with these two lines worked like a charm.  The memory never climbed over 15 MB.

    GC.Collect();
    GC.WaitForPendingFinalizers();

    Again apparently the GC will not "get more agressive" in it's collection till the 40-50MB range.  So calling it earlier will help alot in memory consumption.


    Rad Slide View Solution
    The solution for my rad slide view page did not have to do with the rad slide view itself.
    It was the fault of the page previous linking to the SlideView.  Not everything was being released from  memory so again Everything in the Tree after that point (which included the SlideView) was not being picked up correctly by the GC automatically ( or when I explicitly call it).  I was pushing well over the 90MB App MEM limit for the marketplace requirement.

    I had to set all my resources to null AND un-handle all my events by using the "-=" operator. 
    I was initally still having problems so I commented everything out, till there was no memory stacking effect, and then added line by line back.. .oject by object back and tested each time extensively till I isolated problem points, and then released those problem points explicitly as described above.. .tested and moved on.

    The one i found most interesting was the RadDataBoundListBox, I actually had to release the ItemTemplate... to get the Memory not to stack on elements attached to that visual tree further on down the line(normal text blocks, etc... and in my case RadSlideView).

    Example:
    radLoopingList.ScrollCompleted -= radLoopingList_ScrollCompleted;
    radLoopingList.DataSource = null;
    radLoopingList = null;
    loopLST.ItemNeeded -= loopLST_ItemNeeded;
    loopLST.ItemUpdated -= loopLST_ItemUpdated;
    loopLST = null; 


    lsStuff.ItemTemplate = null;    // lsStuff is a RadDataBoundListBox 
    lsStuff  = null;


    Again this is not Telerik Specific... it's a windows phone memory / Garbage Collection issue.  But if you absolutely need to keep from going over 90MB limit.. then you might want to explicitly release all resource including Telerik  events like example above.

    One more thing I think all should know if they to start to try to get memory efficient before Window'sPhone Tango Release of 90MB limits...

    Do not put all your code to release resources in the back button or the OnNavigationFrom methods.  This will cause a headache when testing the multitasking (long press of back button), because it will erase everything for the page... if you cancel out of the multitasking and go back to your app everything will be blank.

    Instead use the override method
    protected override void OnRemovedFromJournal(System.Windows.Navigation.JournalEntryRemovedEventArgs e)
    {
    }

    This will ensure that your resources are removed after the page has completed exiting


    I was surprised there was things that could trip up the GC... like this.  If you have a basic app you probably would never notice(or care).  But if your app is pushing the bar .. you are likely to notice.


    The next two days I'm working furiously to get my app out the door.... but if you like I'd be happy to isolate down a specific basic example of the above described in a separate test app and send it in.
  6. Kiril Stanoev
    Admin
    Kiril Stanoev avatar
    1511 posts

    Posted 22 Mar 2012 Link to this post

    Hi John,

    Great job with the research. I did not know that WP fires the GC at 40MB and 70MB. For the time being, I don't think we need a sample project. You post is pretty descriptive in that manner. I hope other people will be able to benefit from it.

    I've also updated you Telerik points accordingly. If you have further questions, don't hesitate to contact us.

    Regards,
    Kiril Stanoev
    the Telerik team
    Sharpen your .NET Ninja skills! Attend Q1 webinar week and get a chance to win a license! Book your seat now >>
  7. Cojocaru
    Cojocaru avatar
    6 posts
    Member since:
    Mar 2012

    Posted 19 Apr 2012 Link to this post

    Well solution described above does not work for a large list of images. In my case GC works fine. But I had about 100 of large images in list ( every image about 1 MB). 
    I've solved this problem in this way:
    in my view model I've declared a function that will keep only 2 images on left and 2 images on right (images are downloaded from internet):

    private void PreloadImages(int CurrentImage)
            {
                if (CurrentImage > 0)
                    if (Images[CurrentImage - 1].LowQImage == null)
                        Images[CurrentImage - 1].LowQImage = new BitmapImage(new Uri(String.Format("{0}/03/{1:000}.jpeg", BasePath, CurrentImage)));


                if (CurrentImage > 1)
                    if (Images[CurrentImage - 2].LowQImage == null)
                        Images[CurrentImage - 2].LowQImage = new BitmapImage(new Uri(String.Format("{0}/03/{1:000}.jpeg", BasePath, CurrentImage - 1)));


                if (CurrentImage > 3)
                    if (Images[CurrentImage - 3].LowQImage != null)
                        Images[CurrentImage - 3].LowQImage = null;
                


                if (CurrentImage < TotalPages-1)
                    if (Images[CurrentImage + 1].LowQImage == null)
                        Images[CurrentImage + 1].LowQImage = new BitmapImage(new Uri(String.Format("{0}/03/{1:000}.jpeg", BasePath, CurrentImage + 2)));


                if (CurrentImage < TotalPages-2)
                    if (Images[CurrentImage + 2].LowQImage == null)
                        Images[CurrentImage + 2].LowQImage = new BitmapImage(new Uri(String.Format("{0}/03/{1:000}.jpeg", BasePath, CurrentImage + 3)));


                if (CurrentImage < TotalPages-3)
                    if (Images[CurrentImage + 3].LowQImage != null)
                        Images[CurrentImage + 3].LowQImage = null;
            }

    I call this function in SelectedItem property of my mvc


    public ImageViewModel SelectedItem
            {
                get { return _SelectedItem; }
                set
                {
                   
                    _SelectedItem = value;
                    this.OnPropertyChanged("SelectedItem");
                    if (SelectedChanged != null)
                        SelectedChanged(this, null);
                    if (SelectedItem != null)
                        PreloadImages(SelectedItem.Index);
                }
            }

    Only this solution helped me. Calling gc manually does not help in this case.

    Best regards 
Back to Top
DevCraft banner