Merge

Tue, 22 Oct 2013 12:03:50 -0700

author
jcoomes
date
Tue, 22 Oct 2013 12:03:50 -0700
changeset 6010
0823c8bac468
parent 5953
384c92148c68
parent 6009
c7f403b05168
child 6011
1b422ef5288a

Merge

     1.1 --- a/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp	Mon Oct 21 14:38:11 2013 -0700
     1.2 +++ b/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp	Tue Oct 22 12:03:50 2013 -0700
     1.3 @@ -187,19 +187,23 @@
     1.4    size_t code_root_elems() const { return _code_root_elems; }
     1.5  
     1.6    void print_rs_mem_info_on(outputStream * out, size_t total) {
     1.7 -    out->print_cr("    %8dK (%5.1f%%) by %zd %s regions", round_to_K(rs_mem_size()), rs_mem_size_percent_of(total), amount(), _name);
     1.8 +    out->print_cr("    "SIZE_FORMAT_W(8)"K (%5.1f%%) by "SIZE_FORMAT" %s regions",
     1.9 +        round_to_K(rs_mem_size()), rs_mem_size_percent_of(total), amount(), _name);
    1.10    }
    1.11  
    1.12    void print_cards_occupied_info_on(outputStream * out, size_t total) {
    1.13 -    out->print_cr("     %8d (%5.1f%%) entries by %zd %s regions", cards_occupied(), cards_occupied_percent_of(total), amount(), _name);
    1.14 +    out->print_cr("     "SIZE_FORMAT_W(8)" (%5.1f%%) entries by "SIZE_FORMAT" %s regions",
    1.15 +        cards_occupied(), cards_occupied_percent_of(total), amount(), _name);
    1.16    }
    1.17  
    1.18    void print_code_root_mem_info_on(outputStream * out, size_t total) {
    1.19 -    out->print_cr("    %8dK (%5.1f%%) by %zd %s regions", round_to_K(code_root_mem_size()), code_root_mem_size_percent_of(total), amount(), _name);
    1.20 +    out->print_cr("    "SIZE_FORMAT_W(8)"K (%5.1f%%) by "SIZE_FORMAT" %s regions",
    1.21 +        round_to_K(code_root_mem_size()), code_root_mem_size_percent_of(total), amount(), _name);
    1.22    }
    1.23  
    1.24    void print_code_root_elems_info_on(outputStream * out, size_t total) {
    1.25 -    out->print_cr("     %8d (%5.1f%%) elements by %zd %s regions", code_root_elems(), code_root_elems_percent_of(total), amount(), _name);
    1.26 +    out->print_cr("     "SIZE_FORMAT_W(8)" (%5.1f%%) elements by "SIZE_FORMAT" %s regions",
    1.27 +        code_root_elems(), code_root_elems_percent_of(total), amount(), _name);
    1.28    }
    1.29  };
    1.30  
    1.31 @@ -327,14 +331,14 @@
    1.32    out->print_cr("\n Recent concurrent refinement statistics");
    1.33    out->print_cr("  Processed "SIZE_FORMAT" cards",
    1.34                  num_concurrent_refined_cards());
    1.35 -  out->print_cr("  Of %d completed buffers:", num_processed_buf_total());
    1.36 -  out->print_cr("     %8d (%5.1f%%) by concurrent RS threads.",
    1.37 +  out->print_cr("  Of "SIZE_FORMAT" completed buffers:", num_processed_buf_total());
    1.38 +  out->print_cr("     "SIZE_FORMAT_W(8)" (%5.1f%%) by concurrent RS threads.",
    1.39                  num_processed_buf_total(),
    1.40                  percent_of(num_processed_buf_rs_threads(), num_processed_buf_total()));
    1.41 -  out->print_cr("     %8d (%5.1f%%) by mutator threads.",
    1.42 +  out->print_cr("     "SIZE_FORMAT_W(8)" (%5.1f%%) by mutator threads.",
    1.43                  num_processed_buf_mutator(),
    1.44                  percent_of(num_processed_buf_mutator(), num_processed_buf_total()));
    1.45 -  out->print_cr("  Did %d coarsenings.", num_coarsenings());
    1.46 +  out->print_cr("  Did "SIZE_FORMAT" coarsenings.", num_coarsenings());
    1.47    out->print_cr("  Concurrent RS threads times (s)");
    1.48    out->print("     ");
    1.49    for (uint i = 0; i < _num_vtimes; i++) {
     2.1 --- a/src/share/vm/memory/metaspace.cpp	Mon Oct 21 14:38:11 2013 -0700
     2.2 +++ b/src/share/vm/memory/metaspace.cpp	Tue Oct 22 12:03:50 2013 -0700
     2.3 @@ -75,8 +75,7 @@
     2.4    ClassSmallChunk = 256,
     2.5    SmallChunk = 512,
     2.6    ClassMediumChunk = 4 * K,
     2.7 -  MediumChunk = 8 * K,
     2.8 -  HumongousChunkGranularity = 8
     2.9 +  MediumChunk = 8 * K
    2.10  };
    2.11  
    2.12  static ChunkIndex next_chunk_index(ChunkIndex i) {
    2.13 @@ -92,6 +91,7 @@
    2.14  
    2.15  // Manages the global free lists of chunks.
    2.16  class ChunkManager : public CHeapObj<mtInternal> {
    2.17 +  friend class TestVirtualSpaceNodeTest;
    2.18  
    2.19    // Free list of chunks of different sizes.
    2.20    //   SpecializedChunk
    2.21 @@ -257,6 +257,8 @@
    2.22    // VirtualSpace
    2.23    Metachunk* first_chunk() { return (Metachunk*) bottom(); }
    2.24  
    2.25 +  // Committed but unused space in the virtual space
    2.26 +  size_t free_words_in_vs() const;
    2.27   public:
    2.28  
    2.29    VirtualSpaceNode(size_t byte_size);
    2.30 @@ -301,7 +303,6 @@
    2.31    // used and capacity in this single entry in the list
    2.32    size_t used_words_in_vs() const;
    2.33    size_t capacity_words_in_vs() const;
    2.34 -  size_t free_words_in_vs() const;
    2.35  
    2.36    bool initialize();
    2.37  
    2.38 @@ -319,6 +320,13 @@
    2.39    // in the node from any freelist.
    2.40    void purge(ChunkManager* chunk_manager);
    2.41  
    2.42 +  // If an allocation doesn't fit in the current node a new node is created.
    2.43 +  // Allocate chunks out of the remaining committed space in this node
    2.44 +  // to avoid wasting that memory.
    2.45 +  // This always adds up because all the chunk sizes are multiples of
    2.46 +  // the smallest chunk size.
    2.47 +  void retire(ChunkManager* chunk_manager);
    2.48 +
    2.49  #ifdef ASSERT
    2.50    // Debug support
    2.51    void mangle();
    2.52 @@ -461,6 +469,10 @@
    2.53    // and is typically followed by the allocation of a chunk.
    2.54    bool create_new_virtual_space(size_t vs_word_size);
    2.55  
    2.56 +  // Chunk up the unused committed space in the current
    2.57 +  // virtual space and add the chunks to the free list.
    2.58 +  void retire_current_virtual_space();
    2.59 +
    2.60   public:
    2.61    VirtualSpaceList(size_t word_size);
    2.62    VirtualSpaceList(ReservedSpace rs);
    2.63 @@ -624,10 +636,12 @@
    2.64    bool is_class() { return _mdtype == Metaspace::ClassType; }
    2.65  
    2.66    // Accessors
    2.67 -  size_t specialized_chunk_size() { return SpecializedChunk; }
    2.68 -  size_t small_chunk_size() { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; }
    2.69 -  size_t medium_chunk_size() { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; }
    2.70 -  size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; }
    2.71 +  size_t specialized_chunk_size() { return (size_t) is_class() ? ClassSpecializedChunk : SpecializedChunk; }
    2.72 +  size_t small_chunk_size()       { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; }
    2.73 +  size_t medium_chunk_size()      { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; }
    2.74 +  size_t medium_chunk_bunch()     { return medium_chunk_size() * MediumChunkMultiple; }
    2.75 +
    2.76 +  size_t smallest_chunk_size()  { return specialized_chunk_size(); }
    2.77  
    2.78    size_t allocated_blocks_words() const { return _allocated_blocks_words; }
    2.79    size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; }
    2.80 @@ -1056,6 +1070,35 @@
    2.81  #endif
    2.82  }
    2.83  
    2.84 +void VirtualSpaceList::retire_current_virtual_space() {
    2.85 +  assert_lock_strong(SpaceManager::expand_lock());
    2.86 +
    2.87 +  VirtualSpaceNode* vsn = current_virtual_space();
    2.88 +
    2.89 +  ChunkManager* cm = is_class() ? Metaspace::chunk_manager_class() :
    2.90 +                                  Metaspace::chunk_manager_metadata();
    2.91 +
    2.92 +  vsn->retire(cm);
    2.93 +}
    2.94 +
    2.95 +void VirtualSpaceNode::retire(ChunkManager* chunk_manager) {
    2.96 +  for (int i = (int)MediumIndex; i >= (int)ZeroIndex; --i) {
    2.97 +    ChunkIndex index = (ChunkIndex)i;
    2.98 +    size_t chunk_size = chunk_manager->free_chunks(index)->size();
    2.99 +
   2.100 +    while (free_words_in_vs() >= chunk_size) {
   2.101 +      DEBUG_ONLY(verify_container_count();)
   2.102 +      Metachunk* chunk = get_chunk_vs(chunk_size);
   2.103 +      assert(chunk != NULL, "allocation should have been successful");
   2.104 +
   2.105 +      chunk_manager->return_chunks(index, chunk);
   2.106 +      chunk_manager->inc_free_chunks_total(chunk_size);
   2.107 +      DEBUG_ONLY(verify_container_count();)
   2.108 +    }
   2.109 +  }
   2.110 +  assert(free_words_in_vs() == 0, "should be empty now");
   2.111 +}
   2.112 +
   2.113  VirtualSpaceList::VirtualSpaceList(size_t word_size) :
   2.114                                     _is_class(false),
   2.115                                     _virtual_space_list(NULL),
   2.116 @@ -1181,6 +1224,7 @@
   2.117    if (vs_expanded) {
   2.118      return true;
   2.119    }
   2.120 +  retire_current_virtual_space();
   2.121  
   2.122    // Get another virtual space.
   2.123    size_t grow_vs_words = MAX2((size_t)VirtualSpaceSize, preferred_words);
   2.124 @@ -1902,12 +1946,12 @@
   2.125      chunk_word_size = medium_chunk_size();
   2.126    }
   2.127  
   2.128 -  // Might still need a humongous chunk.  Enforce an
   2.129 -  // eight word granularity to facilitate reuse (some
   2.130 -  // wastage but better chance of reuse).
   2.131 +  // Might still need a humongous chunk.  Enforce
   2.132 +  // humongous allocations sizes to be aligned up to
   2.133 +  // the smallest chunk size.
   2.134    size_t if_humongous_sized_chunk =
   2.135      align_size_up(word_size + Metachunk::overhead(),
   2.136 -                  HumongousChunkGranularity);
   2.137 +                  smallest_chunk_size());
   2.138    chunk_word_size =
   2.139      MAX2((size_t) chunk_word_size, if_humongous_sized_chunk);
   2.140  
   2.141 @@ -2151,10 +2195,10 @@
   2.142      }
   2.143      assert(humongous_chunks->word_size() == (size_t)
   2.144             align_size_up(humongous_chunks->word_size(),
   2.145 -                             HumongousChunkGranularity),
   2.146 +                             smallest_chunk_size()),
   2.147             err_msg("Humongous chunk size is wrong: word size " SIZE_FORMAT
   2.148                     " granularity %d",
   2.149 -                   humongous_chunks->word_size(), HumongousChunkGranularity));
   2.150 +                   humongous_chunks->word_size(), smallest_chunk_size()));
   2.151      Metachunk* next_humongous_chunks = humongous_chunks->next();
   2.152      humongous_chunks->container()->dec_container_count();
   2.153      chunk_manager()->humongous_dictionary()->return_chunk(humongous_chunks);
   2.154 @@ -3301,9 +3345,7 @@
   2.155    }
   2.156  
   2.157    if (result == NULL) {
   2.158 -    report_metadata_oome(loader_data, word_size, mdtype, THREAD);
   2.159 -    // Will not reach here.
   2.160 -    return NULL;
   2.161 +    report_metadata_oome(loader_data, word_size, mdtype, CHECK_NULL);
   2.162    }
   2.163  
   2.164    // Zero initialize.
   2.165 @@ -3494,4 +3536,94 @@
   2.166    TestMetaspaceAuxTest::test();
   2.167  }
   2.168  
   2.169 +class TestVirtualSpaceNodeTest {
   2.170 +  static void chunk_up(size_t words_left, size_t& num_medium_chunks,
   2.171 +                                          size_t& num_small_chunks,
   2.172 +                                          size_t& num_specialized_chunks) {
   2.173 +    num_medium_chunks = words_left / MediumChunk;
   2.174 +    words_left = words_left % MediumChunk;
   2.175 +
   2.176 +    num_small_chunks = words_left / SmallChunk;
   2.177 +    words_left = words_left % SmallChunk;
   2.178 +    // how many specialized chunks can we get?
   2.179 +    num_specialized_chunks = words_left / SpecializedChunk;
   2.180 +    assert(words_left % SpecializedChunk == 0, "should be nothing left");
   2.181 +  }
   2.182 +
   2.183 + public:
   2.184 +  static void test() {
   2.185 +    MutexLockerEx ml(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
   2.186 +    const size_t vsn_test_size_words = MediumChunk  * 4;
   2.187 +    const size_t vsn_test_size_bytes = vsn_test_size_words * BytesPerWord;
   2.188 +
   2.189 +    // The chunk sizes must be multiples of eachother, or this will fail
   2.190 +    STATIC_ASSERT(MediumChunk % SmallChunk == 0);
   2.191 +    STATIC_ASSERT(SmallChunk % SpecializedChunk == 0);
   2.192 +
   2.193 +    { // No committed memory in VSN
   2.194 +      ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk);
   2.195 +      VirtualSpaceNode vsn(vsn_test_size_bytes);
   2.196 +      vsn.initialize();
   2.197 +      vsn.retire(&cm);
   2.198 +      assert(cm.sum_free_chunks_count() == 0, "did not commit any memory in the VSN");
   2.199 +    }
   2.200 +
   2.201 +    { // All of VSN is committed, half is used by chunks
   2.202 +      ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk);
   2.203 +      VirtualSpaceNode vsn(vsn_test_size_bytes);
   2.204 +      vsn.initialize();
   2.205 +      vsn.expand_by(vsn_test_size_words, vsn_test_size_words);
   2.206 +      vsn.get_chunk_vs(MediumChunk);
   2.207 +      vsn.get_chunk_vs(MediumChunk);
   2.208 +      vsn.retire(&cm);
   2.209 +      assert(cm.sum_free_chunks_count() == 2, "should have been memory left for 2 medium chunks");
   2.210 +      assert(cm.sum_free_chunks() == 2*MediumChunk, "sizes should add up");
   2.211 +    }
   2.212 +
   2.213 +    { // 4 pages of VSN is committed, some is used by chunks
   2.214 +      ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk);
   2.215 +      VirtualSpaceNode vsn(vsn_test_size_bytes);
   2.216 +      const size_t page_chunks = 4 * (size_t)os::vm_page_size() / BytesPerWord;
   2.217 +      assert(page_chunks < MediumChunk, "Test expects medium chunks to be at least 4*page_size");
   2.218 +      vsn.initialize();
   2.219 +      vsn.expand_by(page_chunks, page_chunks);
   2.220 +      vsn.get_chunk_vs(SmallChunk);
   2.221 +      vsn.get_chunk_vs(SpecializedChunk);
   2.222 +      vsn.retire(&cm);
   2.223 +
   2.224 +      // committed - used = words left to retire
   2.225 +      const size_t words_left = page_chunks - SmallChunk - SpecializedChunk;
   2.226 +
   2.227 +      size_t num_medium_chunks, num_small_chunks, num_spec_chunks;
   2.228 +      chunk_up(words_left, num_medium_chunks, num_small_chunks, num_spec_chunks);
   2.229 +
   2.230 +      assert(num_medium_chunks == 0, "should not get any medium chunks");
   2.231 +      assert(cm.sum_free_chunks_count() == (num_small_chunks + num_spec_chunks), "should be space for 3 chunks");
   2.232 +      assert(cm.sum_free_chunks() == words_left, "sizes should add up");
   2.233 +    }
   2.234 +
   2.235 +    { // Half of VSN is committed, a humongous chunk is used
   2.236 +      ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk);
   2.237 +      VirtualSpaceNode vsn(vsn_test_size_bytes);
   2.238 +      vsn.initialize();
   2.239 +      vsn.expand_by(MediumChunk * 2, MediumChunk * 2);
   2.240 +      vsn.get_chunk_vs(MediumChunk + SpecializedChunk); // Humongous chunks will be aligned up to MediumChunk + SpecializedChunk
   2.241 +      vsn.retire(&cm);
   2.242 +
   2.243 +      const size_t words_left = MediumChunk * 2 - (MediumChunk + SpecializedChunk);
   2.244 +      size_t num_medium_chunks, num_small_chunks, num_spec_chunks;
   2.245 +      chunk_up(words_left, num_medium_chunks, num_small_chunks, num_spec_chunks);
   2.246 +
   2.247 +      assert(num_medium_chunks == 0, "should not get any medium chunks");
   2.248 +      assert(cm.sum_free_chunks_count() == (num_small_chunks + num_spec_chunks), "should be space for 3 chunks");
   2.249 +      assert(cm.sum_free_chunks() == words_left, "sizes should add up");
   2.250 +    }
   2.251 +
   2.252 +  }
   2.253 +};
   2.254 +
   2.255 +void TestVirtualSpaceNode_test() {
   2.256 +  TestVirtualSpaceNodeTest::test();
   2.257 +}
   2.258 +
   2.259  #endif
     3.1 --- a/src/share/vm/prims/jni.cpp	Mon Oct 21 14:38:11 2013 -0700
     3.2 +++ b/src/share/vm/prims/jni.cpp	Tue Oct 22 12:03:50 2013 -0700
     3.3 @@ -5060,6 +5060,7 @@
     3.4  void TestVirtualSpace_test();
     3.5  void TestMetaspaceAux_test();
     3.6  void TestMetachunk_test();
     3.7 +void TestVirtualSpaceNode_test();
     3.8  #if INCLUDE_ALL_GCS
     3.9  void TestG1BiasedArray_test();
    3.10  #endif
    3.11 @@ -5072,6 +5073,7 @@
    3.12      run_unit_test(TestVirtualSpace_test());
    3.13      run_unit_test(TestMetaspaceAux_test());
    3.14      run_unit_test(TestMetachunk_test());
    3.15 +    run_unit_test(TestVirtualSpaceNode_test());
    3.16      run_unit_test(GlobalDefinitions::test_globals());
    3.17      run_unit_test(GCTimerAllTest::all());
    3.18      run_unit_test(arrayOopDesc::test_max_array_length());
     4.1 --- a/src/share/vm/prims/jvmtiImpl.cpp	Mon Oct 21 14:38:11 2013 -0700
     4.2 +++ b/src/share/vm/prims/jvmtiImpl.cpp	Tue Oct 22 12:03:50 2013 -0700
     4.3 @@ -225,18 +225,20 @@
     4.4    _method = NULL;
     4.5    _bci    = 0;
     4.6    _class_loader = NULL;
     4.7 -#ifdef CHECK_UNHANDLED_OOPS
     4.8 -  // This one is always allocated with new, but check it just in case.
     4.9 -  Thread *thread = Thread::current();
    4.10 -  if (thread->is_in_stack((address)&_method)) {
    4.11 -    thread->allow_unhandled_oop((oop*)&_method);
    4.12 -  }
    4.13 -#endif // CHECK_UNHANDLED_OOPS
    4.14  }
    4.15  
    4.16  JvmtiBreakpoint::JvmtiBreakpoint(Method* m_method, jlocation location) {
    4.17    _method        = m_method;
    4.18    _class_loader  = _method->method_holder()->class_loader_data()->class_loader();
    4.19 +#ifdef CHECK_UNHANDLED_OOPS
    4.20 +  // _class_loader can't be wrapped in a Handle, because JvmtiBreakpoint:s are
    4.21 +  // eventually allocated on the heap.
    4.22 +  //
    4.23 +  // The code handling JvmtiBreakpoint:s allocated on the stack can't be
    4.24 +  // interrupted by a GC until _class_loader is reachable by the GC via the
    4.25 +  // oops_do method.
    4.26 +  Thread::current()->allow_unhandled_oop(&_class_loader);
    4.27 +#endif // CHECK_UNHANDLED_OOPS
    4.28    assert(_method != NULL, "_method != NULL");
    4.29    _bci           = (int) location;
    4.30    assert(_bci >= 0, "_bci >= 0");
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/gc/TestSystemGC.java	Tue Oct 22 12:03:50 2013 -0700
     5.3 @@ -0,0 +1,46 @@
     5.4 +/*
     5.5 +* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     5.6 +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 +*
     5.8 +* This code is free software; you can redistribute it and/or modify it
     5.9 +* under the terms of the GNU General Public License version 2 only, as
    5.10 +* published by the Free Software Foundation.
    5.11 +*
    5.12 +* This code is distributed in the hope that it will be useful, but WITHOUT
    5.13 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.14 +* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.15 +* version 2 for more details (a copy is included in the LICENSE file that
    5.16 +* accompanied this code).
    5.17 +*
    5.18 +* You should have received a copy of the GNU General Public License version
    5.19 +* 2 along with this work; if not, write to the Free Software Foundation,
    5.20 +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.21 +*
    5.22 +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.23 +* or visit www.oracle.com if you need additional information or have any
    5.24 +* questions.
    5.25 +*/
    5.26 +
    5.27 +/*
    5.28 + * @test TestSystemGC
    5.29 + * @key gc
    5.30 + * @summary Runs System.gc() with different flags.
    5.31 + * @run main/othervm TestSystemGC
    5.32 + * @run main/othervm -XX:+UseSerialGC TestSystemGC
    5.33 + * @run main/othervm -XX:+UseParNewGC TestSystemGC
    5.34 + * @run main/othervm -XX:+UseParallelGC TestSystemGC
    5.35 + * @run main/othervm -XX:+UseParallelGC -XX:-UseParallelOldGC TestSystemGC
    5.36 + * @run main/othervm -XX:+UseConcMarkSweepGC TestSystemGC
    5.37 + * @run main/othervm -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent TestSystemGC
    5.38 + * @run main/othervm -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent -XX:-UseParNewGC TestSystemGC
    5.39 + * @run main/othervm -XX:+UseG1GC TestSystemGC
    5.40 + * @run main/othervm -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent TestSystemGC
    5.41 + * @run main/othervm -XX:+UseLargePages TestSystemGC
    5.42 + * @run main/othervm -XX:+UseLargePages -XX:+UseLargePagesInMetaspace TestSystemGC
    5.43 + */
    5.44 +
    5.45 +public class TestSystemGC {
    5.46 +  public static void main(String args[]) throws Exception {
    5.47 +    System.gc();
    5.48 +  }
    5.49 +}

mercurial