annotate src/share/vm/runtime/sweeper.cpp @ 941:8b46c4d82093

4957990: Perm heap bloat in JVM Summary: Treat ProfileData in MDO's as a source of weak, not strong, roots. Fixes the bug for stop-world collection -- the case of concurrent collection will be fixed separately. Reviewed-by: jcoomes, jmasa, kvn, never
author ysr
date Wed, 02 Sep 2009 00:04:29 -0700
parents a61af66fc99e
children 89e0543e1737 54b3b351d6f9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1 /*
a61af66fc99e Initial load
duke
parents:
diff changeset
2 * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
a61af66fc99e Initial load
duke
parents:
diff changeset
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
a61af66fc99e Initial load
duke
parents:
diff changeset
4 *
a61af66fc99e Initial load
duke
parents:
diff changeset
5 * This code is free software; you can redistribute it and/or modify it
a61af66fc99e Initial load
duke
parents:
diff changeset
6 * under the terms of the GNU General Public License version 2 only, as
a61af66fc99e Initial load
duke
parents:
diff changeset
7 * published by the Free Software Foundation.
a61af66fc99e Initial load
duke
parents:
diff changeset
8 *
a61af66fc99e Initial load
duke
parents:
diff changeset
9 * This code is distributed in the hope that it will be useful, but WITHOUT
a61af66fc99e Initial load
duke
parents:
diff changeset
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
a61af66fc99e Initial load
duke
parents:
diff changeset
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
a61af66fc99e Initial load
duke
parents:
diff changeset
12 * version 2 for more details (a copy is included in the LICENSE file that
a61af66fc99e Initial load
duke
parents:
diff changeset
13 * accompanied this code).
a61af66fc99e Initial load
duke
parents:
diff changeset
14 *
a61af66fc99e Initial load
duke
parents:
diff changeset
15 * You should have received a copy of the GNU General Public License version
a61af66fc99e Initial load
duke
parents:
diff changeset
16 * 2 along with this work; if not, write to the Free Software Foundation,
a61af66fc99e Initial load
duke
parents:
diff changeset
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
a61af66fc99e Initial load
duke
parents:
diff changeset
18 *
a61af66fc99e Initial load
duke
parents:
diff changeset
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
a61af66fc99e Initial load
duke
parents:
diff changeset
20 * CA 95054 USA or visit www.sun.com if you need additional information or
a61af66fc99e Initial load
duke
parents:
diff changeset
21 * have any questions.
a61af66fc99e Initial load
duke
parents:
diff changeset
22 *
a61af66fc99e Initial load
duke
parents:
diff changeset
23 */
a61af66fc99e Initial load
duke
parents:
diff changeset
24
a61af66fc99e Initial load
duke
parents:
diff changeset
25 # include "incls/_precompiled.incl"
a61af66fc99e Initial load
duke
parents:
diff changeset
26 # include "incls/_sweeper.cpp.incl"
a61af66fc99e Initial load
duke
parents:
diff changeset
27
a61af66fc99e Initial load
duke
parents:
diff changeset
28 long NMethodSweeper::_traversals = 0; // No. of stack traversals performed
a61af66fc99e Initial load
duke
parents:
diff changeset
29 CodeBlob* NMethodSweeper::_current = NULL; // Current nmethod
a61af66fc99e Initial load
duke
parents:
diff changeset
30 int NMethodSweeper::_seen = 0 ; // No. of blobs we have currently processed in current pass of CodeCache
a61af66fc99e Initial load
duke
parents:
diff changeset
31 int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass
a61af66fc99e Initial load
duke
parents:
diff changeset
32
a61af66fc99e Initial load
duke
parents:
diff changeset
33 jint NMethodSweeper::_locked_seen = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
34 jint NMethodSweeper::_not_entrant_seen_on_stack = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
35 bool NMethodSweeper::_rescan = false;
a61af66fc99e Initial load
duke
parents:
diff changeset
36
a61af66fc99e Initial load
duke
parents:
diff changeset
37 void NMethodSweeper::sweep() {
a61af66fc99e Initial load
duke
parents:
diff changeset
38 assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint");
a61af66fc99e Initial load
duke
parents:
diff changeset
39 if (!MethodFlushing) return;
a61af66fc99e Initial load
duke
parents:
diff changeset
40
a61af66fc99e Initial load
duke
parents:
diff changeset
41 // No need to synchronize access, since this is always executed at a
a61af66fc99e Initial load
duke
parents:
diff changeset
42 // safepoint. If we aren't in the middle of scan and a rescan
a61af66fc99e Initial load
duke
parents:
diff changeset
43 // hasn't been requested then just return.
a61af66fc99e Initial load
duke
parents:
diff changeset
44 if (_current == NULL && !_rescan) return;
a61af66fc99e Initial load
duke
parents:
diff changeset
45
a61af66fc99e Initial load
duke
parents:
diff changeset
46 // Make sure CompiledIC_lock in unlocked, since we might update some
a61af66fc99e Initial load
duke
parents:
diff changeset
47 // inline caches. If it is, we just bail-out and try later.
a61af66fc99e Initial load
duke
parents:
diff changeset
48 if (CompiledIC_lock->is_locked() || Patching_lock->is_locked()) return;
a61af66fc99e Initial load
duke
parents:
diff changeset
49
a61af66fc99e Initial load
duke
parents:
diff changeset
50 // Check for restart
a61af66fc99e Initial load
duke
parents:
diff changeset
51 assert(CodeCache::find_blob_unsafe(_current) == _current, "Sweeper nmethod cached state invalid");
a61af66fc99e Initial load
duke
parents:
diff changeset
52 if (_current == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
53 _seen = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
54 _invocations = NmethodSweepFraction;
a61af66fc99e Initial load
duke
parents:
diff changeset
55 _current = CodeCache::first();
a61af66fc99e Initial load
duke
parents:
diff changeset
56 _traversals += 1;
a61af66fc99e Initial load
duke
parents:
diff changeset
57 if (PrintMethodFlushing) {
a61af66fc99e Initial load
duke
parents:
diff changeset
58 tty->print_cr("### Sweep: stack traversal %d", _traversals);
a61af66fc99e Initial load
duke
parents:
diff changeset
59 }
a61af66fc99e Initial load
duke
parents:
diff changeset
60 Threads::nmethods_do();
a61af66fc99e Initial load
duke
parents:
diff changeset
61
a61af66fc99e Initial load
duke
parents:
diff changeset
62 // reset the flags since we started a scan from the beginning.
a61af66fc99e Initial load
duke
parents:
diff changeset
63 _rescan = false;
a61af66fc99e Initial load
duke
parents:
diff changeset
64 _locked_seen = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
65 _not_entrant_seen_on_stack = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
66 }
a61af66fc99e Initial load
duke
parents:
diff changeset
67
a61af66fc99e Initial load
duke
parents:
diff changeset
68 if (PrintMethodFlushing && Verbose) {
a61af66fc99e Initial load
duke
parents:
diff changeset
69 tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_blobs(), _invocations);
a61af66fc99e Initial load
duke
parents:
diff changeset
70 }
a61af66fc99e Initial load
duke
parents:
diff changeset
71
a61af66fc99e Initial load
duke
parents:
diff changeset
72 // We want to visit all nmethods after NmethodSweepFraction invocations.
a61af66fc99e Initial load
duke
parents:
diff changeset
73 // If invocation is 1 we do the rest
a61af66fc99e Initial load
duke
parents:
diff changeset
74 int todo = CodeCache::nof_blobs();
a61af66fc99e Initial load
duke
parents:
diff changeset
75 if (_invocations != 1) {
a61af66fc99e Initial load
duke
parents:
diff changeset
76 todo = (CodeCache::nof_blobs() - _seen) / _invocations;
a61af66fc99e Initial load
duke
parents:
diff changeset
77 _invocations--;
a61af66fc99e Initial load
duke
parents:
diff changeset
78 }
a61af66fc99e Initial load
duke
parents:
diff changeset
79
a61af66fc99e Initial load
duke
parents:
diff changeset
80 for(int i = 0; i < todo && _current != NULL; i++) {
a61af66fc99e Initial load
duke
parents:
diff changeset
81 CodeBlob* next = CodeCache::next(_current); // Read next before we potentially delete current
a61af66fc99e Initial load
duke
parents:
diff changeset
82 if (_current->is_nmethod()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
83 process_nmethod((nmethod *)_current);
a61af66fc99e Initial load
duke
parents:
diff changeset
84 }
a61af66fc99e Initial load
duke
parents:
diff changeset
85 _seen++;
a61af66fc99e Initial load
duke
parents:
diff changeset
86 _current = next;
a61af66fc99e Initial load
duke
parents:
diff changeset
87 }
a61af66fc99e Initial load
duke
parents:
diff changeset
88 // Because we could stop on a codeBlob other than an nmethod we skip forward
a61af66fc99e Initial load
duke
parents:
diff changeset
89 // to the next nmethod (if any). codeBlobs other than nmethods can be freed
a61af66fc99e Initial load
duke
parents:
diff changeset
90 // async to us and make _current invalid while we sleep.
a61af66fc99e Initial load
duke
parents:
diff changeset
91 while (_current != NULL && !_current->is_nmethod()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
92 _current = CodeCache::next(_current);
a61af66fc99e Initial load
duke
parents:
diff changeset
93 }
a61af66fc99e Initial load
duke
parents:
diff changeset
94
a61af66fc99e Initial load
duke
parents:
diff changeset
95 if (_current == NULL && !_rescan && (_locked_seen || _not_entrant_seen_on_stack)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
96 // we've completed a scan without making progress but there were
a61af66fc99e Initial load
duke
parents:
diff changeset
97 // nmethods we were unable to process either because they were
a61af66fc99e Initial load
duke
parents:
diff changeset
98 // locked or were still on stack. We don't have to aggresively
a61af66fc99e Initial load
duke
parents:
diff changeset
99 // clean them up so just stop scanning. We could scan once more
a61af66fc99e Initial load
duke
parents:
diff changeset
100 // but that complicates the control logic and it's unlikely to
a61af66fc99e Initial load
duke
parents:
diff changeset
101 // matter much.
a61af66fc99e Initial load
duke
parents:
diff changeset
102 if (PrintMethodFlushing) {
a61af66fc99e Initial load
duke
parents:
diff changeset
103 tty->print_cr("### Couldn't make progress on some nmethods so stopping sweep");
a61af66fc99e Initial load
duke
parents:
diff changeset
104 }
a61af66fc99e Initial load
duke
parents:
diff changeset
105 }
a61af66fc99e Initial load
duke
parents:
diff changeset
106 }
a61af66fc99e Initial load
duke
parents:
diff changeset
107
a61af66fc99e Initial load
duke
parents:
diff changeset
108
a61af66fc99e Initial load
duke
parents:
diff changeset
109 void NMethodSweeper::process_nmethod(nmethod *nm) {
a61af66fc99e Initial load
duke
parents:
diff changeset
110 // Skip methods that are currently referenced by the VM
a61af66fc99e Initial load
duke
parents:
diff changeset
111 if (nm->is_locked_by_vm()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
112 // But still remember to clean-up inline caches for alive nmethods
a61af66fc99e Initial load
duke
parents:
diff changeset
113 if (nm->is_alive()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
114 // Clean-up all inline caches that points to zombie/non-reentrant methods
a61af66fc99e Initial load
duke
parents:
diff changeset
115 nm->cleanup_inline_caches();
a61af66fc99e Initial load
duke
parents:
diff changeset
116 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
117 _locked_seen++;
a61af66fc99e Initial load
duke
parents:
diff changeset
118 }
a61af66fc99e Initial load
duke
parents:
diff changeset
119 return;
a61af66fc99e Initial load
duke
parents:
diff changeset
120 }
a61af66fc99e Initial load
duke
parents:
diff changeset
121
a61af66fc99e Initial load
duke
parents:
diff changeset
122 if (nm->is_zombie()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
123 // If it is first time, we see nmethod then we mark it. Otherwise,
a61af66fc99e Initial load
duke
parents:
diff changeset
124 // we reclame it. When we have seen a zombie method twice, we know that
a61af66fc99e Initial load
duke
parents:
diff changeset
125 // there are no inline caches that referes to it.
a61af66fc99e Initial load
duke
parents:
diff changeset
126 if (nm->is_marked_for_reclamation()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
127 assert(!nm->is_locked_by_vm(), "must not flush locked nmethods");
941
8b46c4d82093 4957990: Perm heap bloat in JVM
ysr
parents: 0
diff changeset
128 if (PrintMethodFlushing && Verbose) {
8b46c4d82093 4957990: Perm heap bloat in JVM
ysr
parents: 0
diff changeset
129 tty->print_cr("### Nmethod 0x%x (marked for reclamation) being flushed", nm);
8b46c4d82093 4957990: Perm heap bloat in JVM
ysr
parents: 0
diff changeset
130 }
0
a61af66fc99e Initial load
duke
parents:
diff changeset
131 nm->flush();
a61af66fc99e Initial load
duke
parents:
diff changeset
132 } else {
941
8b46c4d82093 4957990: Perm heap bloat in JVM
ysr
parents: 0
diff changeset
133 if (PrintMethodFlushing && Verbose) {
8b46c4d82093 4957990: Perm heap bloat in JVM
ysr
parents: 0
diff changeset
134 tty->print_cr("### Nmethod 0x%x (zombie) being marked for reclamation", nm);
8b46c4d82093 4957990: Perm heap bloat in JVM
ysr
parents: 0
diff changeset
135 }
0
a61af66fc99e Initial load
duke
parents:
diff changeset
136 nm->mark_for_reclamation();
a61af66fc99e Initial load
duke
parents:
diff changeset
137 _rescan = true;
a61af66fc99e Initial load
duke
parents:
diff changeset
138 }
a61af66fc99e Initial load
duke
parents:
diff changeset
139 } else if (nm->is_not_entrant()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
140 // If there is no current activations of this method on the
a61af66fc99e Initial load
duke
parents:
diff changeset
141 // stack we can safely convert it to a zombie method
a61af66fc99e Initial load
duke
parents:
diff changeset
142 if (nm->can_not_entrant_be_converted()) {
941
8b46c4d82093 4957990: Perm heap bloat in JVM
ysr
parents: 0
diff changeset
143 if (PrintMethodFlushing && Verbose) {
8b46c4d82093 4957990: Perm heap bloat in JVM
ysr
parents: 0
diff changeset
144 tty->print_cr("### Nmethod 0x%x (not entrant) being made zombie", nm);
8b46c4d82093 4957990: Perm heap bloat in JVM
ysr
parents: 0
diff changeset
145 }
0
a61af66fc99e Initial load
duke
parents:
diff changeset
146 nm->make_zombie();
a61af66fc99e Initial load
duke
parents:
diff changeset
147 _rescan = true;
a61af66fc99e Initial load
duke
parents:
diff changeset
148 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
149 // Still alive, clean up its inline caches
a61af66fc99e Initial load
duke
parents:
diff changeset
150 nm->cleanup_inline_caches();
a61af66fc99e Initial load
duke
parents:
diff changeset
151 // we coudn't transition this nmethod so don't immediately
a61af66fc99e Initial load
duke
parents:
diff changeset
152 // request a rescan. If this method stays on the stack for a
a61af66fc99e Initial load
duke
parents:
diff changeset
153 // long time we don't want to keep rescanning at every safepoint.
a61af66fc99e Initial load
duke
parents:
diff changeset
154 _not_entrant_seen_on_stack++;
a61af66fc99e Initial load
duke
parents:
diff changeset
155 }
a61af66fc99e Initial load
duke
parents:
diff changeset
156 } else if (nm->is_unloaded()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
157 // Unloaded code, just make it a zombie
941
8b46c4d82093 4957990: Perm heap bloat in JVM
ysr
parents: 0
diff changeset
158 if (PrintMethodFlushing && Verbose)
8b46c4d82093 4957990: Perm heap bloat in JVM
ysr
parents: 0
diff changeset
159 tty->print_cr("### Nmethod 0x%x (unloaded) being made zombie", nm);
8b46c4d82093 4957990: Perm heap bloat in JVM
ysr
parents: 0
diff changeset
160 if (nm->is_osr_method()) {
0
a61af66fc99e Initial load
duke
parents:
diff changeset
161 // No inline caches will ever point to osr methods, so we can just remove it
a61af66fc99e Initial load
duke
parents:
diff changeset
162 nm->flush();
a61af66fc99e Initial load
duke
parents:
diff changeset
163 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
164 nm->make_zombie();
a61af66fc99e Initial load
duke
parents:
diff changeset
165 _rescan = true;
a61af66fc99e Initial load
duke
parents:
diff changeset
166 }
a61af66fc99e Initial load
duke
parents:
diff changeset
167 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
168 assert(nm->is_alive(), "should be alive");
a61af66fc99e Initial load
duke
parents:
diff changeset
169 // Clean-up all inline caches that points to zombie/non-reentrant methods
a61af66fc99e Initial load
duke
parents:
diff changeset
170 nm->cleanup_inline_caches();
a61af66fc99e Initial load
duke
parents:
diff changeset
171 }
a61af66fc99e Initial load
duke
parents:
diff changeset
172 }