Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_hotspot
提交
560a1897
D
dragonwell8_hotspot
项目概览
openanolis
/
dragonwell8_hotspot
通知
2
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_hotspot
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
560a1897
编写于
6月 03, 2010
作者:
A
acorn
浏览文件
操作
浏览文件
下载
差异文件
Merge
上级
db7077c0
90c2361f
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
220 addition
and
53 deletion
+220
-53
src/share/vm/runtime/globals.hpp
src/share/vm/runtime/globals.hpp
+4
-0
src/share/vm/runtime/synchronizer.cpp
src/share/vm/runtime/synchronizer.cpp
+210
-52
src/share/vm/runtime/synchronizer.hpp
src/share/vm/runtime/synchronizer.hpp
+2
-0
src/share/vm/runtime/thread.cpp
src/share/vm/runtime/thread.cpp
+2
-0
src/share/vm/runtime/thread.hpp
src/share/vm/runtime/thread.hpp
+2
-1
未找到文件。
src/share/vm/runtime/globals.hpp
浏览文件 @
560a1897
...
...
@@ -920,6 +920,10 @@ class CommandLineFlags {
\
product(intx, AlwaysInflate, 0, "(Unstable) Force inflation") \
\
product(intx, MonitorBound, 0, "Bound Monitor population") \
\
product(bool, MonitorInUseLists, false, "Track Monitors for Deflation") \
\
product(intx, Atomics, 0, \
"(Unsafe,Unstable) Diagnostic - Controls emission of atomics") \
\
...
...
src/share/vm/runtime/synchronizer.cpp
浏览文件 @
560a1897
...
...
@@ -185,6 +185,8 @@ struct SharedGlobals {
}
;
static
SharedGlobals
GVars
;
static
int
MonitorScavengeThreshold
=
1000000
;
static
volatile
int
ForceMonitorScavenge
=
0
;
// Scavenge required and pending
// Tunables ...
...
...
@@ -746,8 +748,85 @@ void Thread::muxRelease (volatile intptr_t * Lock) {
ObjectMonitor
*
ObjectSynchronizer
::
gBlockList
=
NULL
;
ObjectMonitor
*
volatile
ObjectSynchronizer
::
gFreeList
=
NULL
;
static
volatile
intptr_t
ListLock
=
0
;
// protects global monitor free-list cache
static
volatile
int
MonitorFreeCount
=
0
;
// # on gFreeList
static
volatile
int
MonitorPopulation
=
0
;
// # Extant -- in circulation
#define CHAINMARKER ((oop)-1)
// Constraining monitor pool growth via MonitorBound ...
//
// The monitor pool is grow-only. We scavenge at STW safepoint-time, but the
// the rate of scavenging is driven primarily by GC. As such, we can find
// an inordinate number of monitors in circulation.
// To avoid that scenario we can artificially induce a STW safepoint
// if the pool appears to be growing past some reasonable bound.
// Generally we favor time in space-time tradeoffs, but as there's no
// natural back-pressure on the # of extant monitors we need to impose some
// type of limit. Beware that if MonitorBound is set to too low a value
// we could just loop. In addition, if MonitorBound is set to a low value
// we'll incur more safepoints, which are harmful to performance.
// See also: GuaranteedSafepointInterval
//
// As noted elsewhere, the correct long-term solution is to deflate at
// monitorexit-time, in which case the number of inflated objects is bounded
// by the number of threads. That policy obviates the need for scavenging at
// STW safepoint time. As an aside, scavenging can be time-consuming when the
// # of extant monitors is large. Unfortunately there's a day-1 assumption baked
// into much HotSpot code that the object::monitor relationship, once established
// or observed, will remain stable except over potential safepoints.
//
// We can use either a blocking synchronous VM operation or an async VM operation.
// -- If we use a blocking VM operation :
// Calls to ScavengeCheck() should be inserted only into 'safe' locations in paths
// that lead to ::inflate() or ::omAlloc().
// Even though the safepoint will not directly induce GC, a GC might
// piggyback on the safepoint operation, so the caller should hold no naked oops.
// Furthermore, monitor::object relationships are NOT necessarily stable over this call
// unless the caller has made provisions to "pin" the object to the monitor, say
// by incrementing the monitor's _count field.
// -- If we use a non-blocking asynchronous VM operation :
// the constraints above don't apply. The safepoint will fire in the future
// at a more convenient time. On the other hand the latency between posting and
// running the safepoint introduces or admits "slop" or laxity during which the
// monitor population can climb further above the threshold. The monitor population,
// however, tends to converge asymptotically over time to a count that's slightly
// above the target value specified by MonitorBound. That is, we avoid unbounded
// growth, albeit with some imprecision.
//
// The current implementation uses asynchronous VM operations.
//
// Ideally we'd check if (MonitorPopulation > MonitorBound) in omAlloc()
// immediately before trying to grow the global list via allocation.
// If the predicate was true then we'd induce a synchronous safepoint, wait
// for the safepoint to complete, and then again to allocate from the global
// free list. This approach is much simpler and precise, admitting no "slop".
// Unfortunately we can't safely safepoint in the midst of omAlloc(), so
// instead we use asynchronous safepoints.
static
void
InduceScavenge
(
Thread
*
Self
,
const
char
*
Whence
)
{
// Induce STW safepoint to trim monitors
// Ultimately, this results in a call to deflate_idle_monitors() in the near future.
// More precisely, trigger an asynchronous STW safepoint as the number
// of active monitors passes the specified threshold.
// TODO: assert thread state is reasonable
if
(
ForceMonitorScavenge
==
0
&&
Atomic
::
xchg
(
1
,
&
ForceMonitorScavenge
)
==
0
)
{
if
(
Knob_Verbose
)
{
::
printf
(
"Monitor scavenge - Induced STW @%s (%d)
\n
"
,
Whence
,
ForceMonitorScavenge
)
;
::
fflush
(
stdout
)
;
}
// Induce a 'null' safepoint to scavenge monitors
// Must VM_Operation instance be heap allocated as the op will be enqueue and posted
// to the VMthread and have a lifespan longer than that of this activation record.
// The VMThread will delete the op when completed.
VMThread
::
execute
(
new
VM_ForceAsyncSafepoint
())
;
if
(
Knob_Verbose
)
{
::
printf
(
"Monitor scavenge - STW posted @%s (%d)
\n
"
,
Whence
,
ForceMonitorScavenge
)
;
::
fflush
(
stdout
)
;
}
}
}
ObjectMonitor
*
ATTR
ObjectSynchronizer
::
omAlloc
(
Thread
*
Self
)
{
// A large MAXPRIVATE value reduces both list lock contention
// and list coherency traffic, but also tends to increase the
...
...
@@ -770,6 +849,11 @@ ObjectMonitor * ATTR ObjectSynchronizer::omAlloc (Thread * Self) {
Self
->
omFreeCount
--
;
// CONSIDER: set m->FreeNext = BAD -- diagnostic hygiene
guarantee
(
m
->
object
()
==
NULL
,
"invariant"
)
;
if
(
MonitorInUseLists
)
{
m
->
FreeNext
=
Self
->
omInUseList
;
Self
->
omInUseList
=
m
;
Self
->
omInUseCount
++
;
}
return
m
;
}
...
...
@@ -784,6 +868,7 @@ ObjectMonitor * ATTR ObjectSynchronizer::omAlloc (Thread * Self) {
// on various locks.
Thread
::
muxAcquire
(
&
ListLock
,
"omAlloc"
)
;
for
(
int
i
=
Self
->
omFreeProvision
;
--
i
>=
0
&&
gFreeList
!=
NULL
;
)
{
MonitorFreeCount
--
;
ObjectMonitor
*
take
=
gFreeList
;
gFreeList
=
take
->
FreeNext
;
guarantee
(
take
->
object
()
==
NULL
,
"invariant"
)
;
...
...
@@ -796,6 +881,15 @@ ObjectMonitor * ATTR ObjectSynchronizer::omAlloc (Thread * Self) {
if
(
Self
->
omFreeProvision
>
MAXPRIVATE
)
Self
->
omFreeProvision
=
MAXPRIVATE
;
TEVENT
(
omFirst
-
reprovision
)
;
continue
;
const
int
mx
=
MonitorBound
;
if
(
mx
>
0
&&
(
MonitorPopulation
-
MonitorFreeCount
)
>
mx
)
{
// We can't safely induce a STW safepoint from omAlloc() as our thread
// state may not be appropriate for such activities and callers may hold
// naked oops, so instead we defer the action.
InduceScavenge
(
Self
,
"omAlloc"
)
;
}
continue
;
}
// 3: allocate a block of new ObjectMonitors
...
...
@@ -836,6 +930,8 @@ ObjectMonitor * ATTR ObjectSynchronizer::omAlloc (Thread * Self) {
// Acquire the ListLock to manipulate BlockList and FreeList.
// An Oyama-Taura-Yonezawa scheme might be more efficient.
Thread
::
muxAcquire
(
&
ListLock
,
"omAlloc [2]"
)
;
MonitorPopulation
+=
_BLOCKSIZE
-
1
;
MonitorFreeCount
+=
_BLOCKSIZE
-
1
;
// Add the new block to the list of extant blocks (gBlockList).
// The very first objectMonitor in a block is reserved and dedicated.
...
...
@@ -894,7 +990,9 @@ void ObjectSynchronizer::omFlush (Thread * Self) {
if
(
List
==
NULL
)
return
;
ObjectMonitor
*
Tail
=
NULL
;
ObjectMonitor
*
s
;
int
Tally
=
0
;
for
(
s
=
List
;
s
!=
NULL
;
s
=
s
->
FreeNext
)
{
Tally
++
;
Tail
=
s
;
guarantee
(
s
->
object
()
==
NULL
,
"invariant"
)
;
guarantee
(
!
s
->
is_busy
(),
"invariant"
)
;
...
...
@@ -906,6 +1004,7 @@ void ObjectSynchronizer::omFlush (Thread * Self) {
Thread
::
muxAcquire
(
&
ListLock
,
"omFlush"
)
;
Tail
->
FreeNext
=
gFreeList
;
gFreeList
=
List
;
MonitorFreeCount
+=
Tally
;
Thread
::
muxRelease
(
&
ListLock
)
;
TEVENT
(
omFlush
)
;
}
...
...
@@ -1747,16 +1846,15 @@ void ObjectSynchronizer::oops_do(OopClosure* f) {
// Having a large number of monitors in-circulation negatively
// impacts the performance of some applications (e.g., PointBase).
// Broadly, we want to minimize the # of monitors in circulation.
// Alternately, we could partition the active monitors into sub-lists
// of those that need scanning and those that do not.
// Specifically, we would add a new sub-list of objectmonitors
// that are in-circulation and potentially active. deflate_idle_monitors()
// would scan only that list. Other monitors could reside on a quiescent
// list. Such sequestered monitors wouldn't need to be scanned by
// deflate_idle_monitors(). omAlloc() would first check the global free list,
// then the quiescent list, and, failing those, would allocate a new block.
// Deflate_idle_monitors() would scavenge and move monitors to the
// quiescent list.
//
// We have added a flag, MonitorInUseLists, which creates a list
// of active monitors for each thread. deflate_idle_monitors()
// only scans the per-thread inuse lists. omAlloc() puts all
// assigned monitors on the per-thread list. deflate_idle_monitors()
// returns the non-busy monitors to the global free list.
// An alternative could have used a single global inuse list. The
// downside would have been the additional cost of acquiring the global list lock
// for every omAlloc().
//
// Perversely, the heap size -- and thus the STW safepoint rate --
// typically drives the scavenge rate. Large heaps can mean infrequent GC,
...
...
@@ -1769,18 +1867,100 @@ void ObjectSynchronizer::oops_do(OopClosure* f) {
// An even better solution would be to deflate on-the-fly, aggressively,
// at monitorexit-time as is done in EVM's metalock or Relaxed Locks.
// Deflate a single monitor if not in use
// Return true if deflated, false if in use
bool
ObjectSynchronizer
::
deflate_monitor
(
ObjectMonitor
*
mid
,
oop
obj
,
ObjectMonitor
**
FreeHeadp
,
ObjectMonitor
**
FreeTailp
)
{
bool
deflated
;
// Normal case ... The monitor is associated with obj.
guarantee
(
obj
->
mark
()
==
markOopDesc
::
encode
(
mid
),
"invariant"
)
;
guarantee
(
mid
==
obj
->
mark
()
->
monitor
(),
"invariant"
);
guarantee
(
mid
->
header
()
->
is_neutral
(),
"invariant"
);
if
(
mid
->
is_busy
())
{
if
(
ClearResponsibleAtSTW
)
mid
->
_Responsible
=
NULL
;
deflated
=
false
;
}
else
{
// Deflate the monitor if it is no longer being used
// It's idle - scavenge and return to the global free list
// plain old deflation ...
TEVENT
(
deflate_idle_monitors
-
scavenge1
)
;
if
(
TraceMonitorInflation
)
{
if
(
obj
->
is_instance
())
{
ResourceMark
rm
;
tty
->
print_cr
(
"Deflating object "
INTPTR_FORMAT
" , mark "
INTPTR_FORMAT
" , type %s"
,
(
intptr_t
)
obj
,
(
intptr_t
)
obj
->
mark
(),
Klass
::
cast
(
obj
->
klass
())
->
external_name
());
}
}
// Restore the header back to obj
obj
->
release_set_mark
(
mid
->
header
());
mid
->
clear
();
assert
(
mid
->
object
()
==
NULL
,
"invariant"
)
;
// Move the object to the working free list defined by FreeHead,FreeTail.
if
(
*
FreeHeadp
==
NULL
)
*
FreeHeadp
=
mid
;
if
(
*
FreeTailp
!=
NULL
)
{
ObjectMonitor
*
prevtail
=
*
FreeTailp
;
prevtail
->
FreeNext
=
mid
;
}
*
FreeTailp
=
mid
;
deflated
=
true
;
}
return
deflated
;
}
void
ObjectSynchronizer
::
deflate_idle_monitors
()
{
assert
(
SafepointSynchronize
::
is_at_safepoint
(),
"must be at safepoint"
);
int
nInuse
=
0
;
// currently associated with objects
int
nInCirculation
=
0
;
// extant
int
nScavenged
=
0
;
// reclaimed
bool
deflated
=
false
;
ObjectMonitor
*
FreeHead
=
NULL
;
// Local SLL of scavenged monitors
ObjectMonitor
*
FreeTail
=
NULL
;
// Iterate over all extant monitors - Scavenge all idle monitors.
TEVENT
(
deflate_idle_monitors
)
;
for
(
ObjectMonitor
*
block
=
gBlockList
;
block
!=
NULL
;
block
=
next
(
block
))
{
// Prevent omFlush from changing mids in Thread dtor's during deflation
// And in case the vm thread is acquiring a lock during a safepoint
// See e.g. 6320749
Thread
::
muxAcquire
(
&
ListLock
,
"scavenge - return"
)
;
if
(
MonitorInUseLists
)
{
ObjectMonitor
*
mid
;
ObjectMonitor
*
next
;
ObjectMonitor
*
curmidinuse
;
for
(
JavaThread
*
cur
=
Threads
::
first
();
cur
!=
NULL
;
cur
=
cur
->
next
())
{
curmidinuse
=
NULL
;
for
(
mid
=
cur
->
omInUseList
;
mid
!=
NULL
;
)
{
oop
obj
=
(
oop
)
mid
->
object
();
deflated
=
false
;
if
(
obj
!=
NULL
)
{
deflated
=
deflate_monitor
(
mid
,
obj
,
&
FreeHead
,
&
FreeTail
);
}
if
(
deflated
)
{
// extract from per-thread in-use-list
if
(
mid
==
cur
->
omInUseList
)
{
cur
->
omInUseList
=
mid
->
FreeNext
;
}
else
if
(
curmidinuse
!=
NULL
)
{
curmidinuse
->
FreeNext
=
mid
->
FreeNext
;
// maintain the current thread inuselist
}
next
=
mid
->
FreeNext
;
mid
->
FreeNext
=
NULL
;
// This mid is current tail in the FreeHead list
mid
=
next
;
cur
->
omInUseCount
--
;
nScavenged
++
;
}
else
{
curmidinuse
=
mid
;
mid
=
mid
->
FreeNext
;
nInuse
++
;
}
}
}
}
else
for
(
ObjectMonitor
*
block
=
gBlockList
;
block
!=
NULL
;
block
=
next
(
block
))
{
// Iterate over all extant monitors - Scavenge all idle monitors.
assert
(
block
->
object
()
==
CHAINMARKER
,
"must be a block header"
);
nInCirculation
+=
_BLOCKSIZE
;
for
(
int
i
=
1
;
i
<
_BLOCKSIZE
;
i
++
)
{
...
...
@@ -1795,61 +1975,39 @@ void ObjectSynchronizer::deflate_idle_monitors() {
guarantee
(
!
mid
->
is_busy
(),
"invariant"
)
;
continue
;
}
deflated
=
deflate_monitor
(
mid
,
obj
,
&
FreeHead
,
&
FreeTail
);
// Normal case ... The monitor is associated with obj.
guarantee
(
obj
->
mark
()
==
markOopDesc
::
encode
(
mid
),
"invariant"
)
;
guarantee
(
mid
==
obj
->
mark
()
->
monitor
(),
"invariant"
);
guarantee
(
mid
->
header
()
->
is_neutral
(),
"invariant"
);
if
(
mid
->
is_busy
())
{
if
(
ClearResponsibleAtSTW
)
mid
->
_Responsible
=
NULL
;
nInuse
++
;
if
(
deflated
)
{
mid
->
FreeNext
=
NULL
;
nScavenged
++
;
}
else
{
// Deflate the monitor if it is no longer being used
// It's idle - scavenge and return to the global free list
// plain old deflation ...
TEVENT
(
deflate_idle_monitors
-
scavenge1
)
;
if
(
TraceMonitorInflation
)
{
if
(
obj
->
is_instance
())
{
ResourceMark
rm
;
tty
->
print_cr
(
"Deflating object "
INTPTR_FORMAT
" , mark "
INTPTR_FORMAT
" , type %s"
,
(
intptr_t
)
obj
,
(
intptr_t
)
obj
->
mark
(),
Klass
::
cast
(
obj
->
klass
())
->
external_name
());
}
}
nInuse
++
;
}
}
}
// Restore the header back to obj
obj
->
release_set_mark
(
mid
->
header
());
mid
->
clear
();
MonitorFreeCount
+=
nScavenged
;
assert
(
mid
->
object
()
==
NULL
,
"invariant"
)
;
// Consider: audit gFreeList to ensure that MonitorFreeCount and list agree.
// Move the object to the working free list defined by FreeHead,FreeTail.
mid
->
FreeNext
=
NULL
;
if
(
FreeHead
==
NULL
)
FreeHead
=
mid
;
if
(
FreeTail
!=
NULL
)
FreeTail
->
FreeNext
=
mid
;
FreeTail
=
mid
;
nScavenged
++
;
}
}
if
(
Knob_Verbose
)
{
::
printf
(
"Deflate: InCirc=%d InUse=%d Scavenged=%d ForceMonitorScavenge=%d : pop=%d free=%d
\n
"
,
nInCirculation
,
nInuse
,
nScavenged
,
ForceMonitorScavenge
,
MonitorPopulation
,
MonitorFreeCount
)
;
::
fflush
(
stdout
)
;
}
ForceMonitorScavenge
=
0
;
// Reset
// Move the scavenged monitors back to the global free list.
// In theory we don't need the freelist lock as we're at a STW safepoint.
// omAlloc() and omFree() can only be called while a thread is _not in safepoint state.
// But it's remotely possible that omFlush() or release_monitors_owned_by_thread()
// might be called while not at a global STW safepoint. In the interest of
// safety we protect the following access with ListLock.
// An even more conservative and prudent approach would be to guard
// the main loop in scavenge_idle_monitors() with ListLock.
if
(
FreeHead
!=
NULL
)
{
guarantee
(
FreeTail
!=
NULL
&&
nScavenged
>
0
,
"invariant"
)
;
assert
(
FreeTail
->
FreeNext
==
NULL
,
"invariant"
)
;
// constant-time list splice - prepend scavenged segment to gFreeList
Thread
::
muxAcquire
(
&
ListLock
,
"scavenge - return"
)
;
FreeTail
->
FreeNext
=
gFreeList
;
gFreeList
=
FreeHead
;
Thread
::
muxRelease
(
&
ListLock
)
;
}
Thread
::
muxRelease
(
&
ListLock
)
;
if
(
_sync_Deflations
!=
NULL
)
_sync_Deflations
->
inc
(
nScavenged
)
;
if
(
_sync_MonExtant
!=
NULL
)
_sync_MonExtant
->
set_value
(
nInCirculation
);
...
...
src/share/vm/runtime/synchronizer.hpp
浏览文件 @
560a1897
...
...
@@ -150,6 +150,8 @@ class ObjectSynchronizer : AllStatic {
// Basically we deflate all monitors that are not busy.
// An adaptive profile-based deflation policy could be used if needed
static
void
deflate_idle_monitors
();
static
bool
deflate_monitor
(
ObjectMonitor
*
mid
,
oop
obj
,
ObjectMonitor
**
FreeHeadp
,
ObjectMonitor
**
FreeTailp
);
static
void
oops_do
(
OopClosure
*
f
);
// debugging
...
...
src/share/vm/runtime/thread.cpp
浏览文件 @
560a1897
...
...
@@ -139,6 +139,8 @@ Thread::Thread() {
omFreeList
=
NULL
;
omFreeCount
=
0
;
omFreeProvision
=
32
;
omInUseList
=
NULL
;
omInUseCount
=
0
;
_SR_lock
=
new
Monitor
(
Mutex
::
suspend_resume
,
"SR_lock"
,
true
);
_suspend_flags
=
0
;
...
...
src/share/vm/runtime/thread.hpp
浏览文件 @
560a1897
...
...
@@ -225,6 +225,8 @@ class Thread: public ThreadShadow {
ObjectMonitor
*
omFreeList
;
int
omFreeCount
;
// length of omFreeList
int
omFreeProvision
;
// reload chunk size
ObjectMonitor
*
omInUseList
;
// SLL to track monitors in circulation
int
omInUseCount
;
// length of omInUseList
public:
enum
{
...
...
@@ -493,7 +495,6 @@ public:
static
ByteSize
stack_base_offset
()
{
return
byte_offset_of
(
Thread
,
_stack_base
);
}
static
ByteSize
stack_size_offset
()
{
return
byte_offset_of
(
Thread
,
_stack_size
);
}
static
ByteSize
omFreeList_offset
()
{
return
byte_offset_of
(
Thread
,
omFreeList
);
}
#define TLAB_FIELD_OFFSET(name) \
static ByteSize tlab_##name##_offset() { return byte_offset_of(Thread, _tlab) + ThreadLocalAllocBuffer::name##_offset(); }
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录