JDK-4727676 : MarkSweepAlwaysCompactCount causes unpredictable memory allocation
  • Type: Bug
  • Component: hotspot
  • Sub-Component: gc
  • Affected Version: 1.3.1,1.4.0,1.4.1,1.4.2
  • Priority: P3
  • Status: Closed
  • Resolution: Other
  • OS: generic
  • CPU: generic
  • Submitted: 2002-08-07
  • Updated: 2012-10-03
  • Resolved: 2012-10-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.2 mantisResolved
Related Reports
Relates :  
Description
###@###.### 2002-08-07

While chasing the following bug:

4701980 2/2 HPROF: -Xrunhprof option crashes and restarts S1AS app server

I wrote a test case to look for memory leaks when running a JVM/PI
agent. This test case has a simple algorithm:

1) allocate 1MB chunks until the heap runs out of memory
2) find a working block size < 1MB that can be allocated
3) allocate and free the working block size for N seconds
4) verify that the heap still has < 1MB left

When the test is run without any VM options, an OutOfMemoryError will
be quickly thrown:

    % java -version
    java version "1.4.0"
    Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
    Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)
    % java b4727676
    b4727676: starting test.
    Allocated 62MB before getting OutOfMemoryError.
    Remainder of test will run for 30 seconds.
    Working block size is 786432 bytes.
    Could not allocate 786432 bytes after 0 attempts.
    Unexpected exception: java.lang.Exception: b4727676: test FAILed.
    Exception in thread "main" java.lang.Exception: b4727676: test FAILed.
            at b4727676.main(b4727676.java:15)

When the test is run with the '-XX:MarkSweepAlwaysCompactCount=1' option,
then the test passes:

    java -XX:MarkSweepAlwaysCompactCount=1 b4727676
    b4727676: starting test.
    Allocated 62MB before getting OutOfMemoryError.
    Remainder of test will run for 30 seconds.
    Working block size is 786432 bytes.
    Allocated and released working block 1323 times.
    Heap still has < 1MB of memory.
    b4727676: test PASSed.

The default value of MarkSweepAlwaysCompactCount is 4 which means that
dead objects are only compacted every fourth GC (maybe full GC). This
can lead to unpredictable results in low memory situations. It may even
been the root cause for some of our spurious OutOfMemoryError bug
reports.

I have attached the test as b4727676.java.

Comments
Been in resolved state for more than ten years. Closing.
03-10-2012

CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: generic mantis FIXED IN: mantis INTEGRATED IN: mantis
14-06-2004

EVALUATION This looks like a good idea, as long as we apply it only to the bailout full-gc case. I would change the code a bit to something like this: // We want to make sure the bail-out case gets as much memory as // possible. Collect all soft references, and fully compact the // heap. { IntFlagSetting(MarkSweepAlwaysCompactCount, 1); do_gc(...); } allocation_attempt(...); }
11-06-2004

SUGGESTED FIX ###@###.### 2002-08-07 Here is the suggested fix for the bug: ------- src/share/vm/memory/collectorPolicy.cpp ------- *** /tmp/sccs.Cdaiqf Wed Aug 7 10:12:46 2002 --- collectorPolicy.cpp Wed Aug 7 10:07:58 2002 *************** *** 300,305 **** --- 300,326 ---- assert(gch->is_in(result), "result not in heap"); return result; } + + if (MarkSweepAlwaysCompactCount != 1) { + // Temporarily try always compacting + intx old_value = MarkSweepAlwaysCompactCount; // save current value + MarkSweepAlwaysCompactCount = 1; // force compaction + + gch->do_collection(true /* full */, + true /* clear_all_soft_refs */, + size /* size */, + is_large_noref /* is_large_noref */, + is_tlab /* is_tlab */, + number_of_generations() - 1 /* max_level */, + notify_ref_lock /* notify_ref_lock */); + MarkSweepAlwaysCompactCount = old_value; // restore previous value + + result = gch->attempt_allocation(size, is_large_noref, is_tlab, false /* first_only */); + if (result != NULL) { + assert(gch->is_in(result), "result not in heap"); + return result; + } + } // What else? We might try synchronous finalization later. If the total // space available is large enough for the allocation, then a more
11-06-2004