Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6448405

static HashMap cache in LineBreakMeasurer can grow wihout bounds

    Details

    • Type: Bug
    • Status: Closed
    • Priority: P3
    • Resolution: Fixed
    • Affects Version/s: 5.0
    • Fix Version/s: 7
    • Component/s: client-libs
    • Labels:
    • Subcomponent:
      2d
    • Resolved In Build:
      b03
    • CPU:
      x86
    • OS:
      windows_xp
    • Verification:
      Verified

      Backports

        Description

        FULL PRODUCT VERSION :
        java version "1.5.0_05"
        Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_05-b05)
        Java HotSpot(TM) Client VM (build 1.5.0_05-b05, mixed mode, sharing)

        ADDITIONAL OS VERSION INFORMATION :
        Microsoft Windows XP [Version 5.1.2600]

        A DESCRIPTION OF THE PROBLEM :
        The FontRenderContext that is given to the constructor of the LineBreakManager contains a AffineTransform object.
        The 6 double values (scale/shear/transform) inside this AffineTransform object all are part of the key that is used to fill the static hashmap "SDCache" in class "sun.font.GlyphLayout".
        The transform-x/y values in the AffineTransform are most of the cases different values, because different texts are painted on different points on the screen. The transform-x/y values are not needed by the LineBreakMeasurer: a string is just as long on any place on the screen.
        In my app, eventually the static cache consumes 100MB of the java heap after it has been filled with 250000+ FontRenderContext objects!

        In my opinion this is a slowly progressing memory leak.

        OutOfMemory errors and a big windows VM size for java.exe are the result.

        Solution: don't use the transforn-x/y values in the key in the hashmap.
        I cleared then in the FontRenderContext before constructing the LineBreakMeasurer and the hashmap did not grow more than 3 FontRenderContext objects.



        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Use a LineBreakMeasurer object to measure text.
        Use a new LineBreakMeasurer object for every consequtive text.
        Supply the FontRenderContext that you get from a Graphics2D instance to the constructor for the LineBreakMeasurer.
        But first set the Graphics2D context at the translation point for where you intend to paint the text on the screen. These coordinates will be different for each text you paint (else you cannot read the texts on the screen!)

        You will see the number of sun.font.GlyphLayout$SDCache objects grow in your memory profiler. All these objects are held in a static hashmap, so garbage collection does not remove them from the heap.


        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        I would expect that caching would stay within limits.
        Do not use the transform-x/y values in the key for the cache.
        ACTUAL -
        The transform-x/y values are used in the key for the cache and so the cache grows beyond proportions after enough time and repainting.


        ERROR MESSAGES/STACK TRACES THAT OCCUR :
        Moved to commments section.

        REPRODUCIBILITY :
        This bug can be reproduced always.

          Attachments

            Issue Links

              Activity

                People

                • Assignee:
                  prr Philip Race
                  Reporter:
                  ndcosta Nelson Dcosta (Inactive)
                • Votes:
                  0 Vote for this issue
                  Watchers:
                  0 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved:
                    Imported:
                    Indexed: