Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
ae7f1139
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
3
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
ae7f1139
编写于
6月 22, 2010
作者:
O
ohair
浏览文件
操作
浏览文件
下载
差异文件
Merge
上级
12a6372d
6ccf5ac2
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
833 addition
and
32 deletion
+833
-32
src/share/classes/java/util/logging/LogManager.java
src/share/classes/java/util/logging/LogManager.java
+141
-18
src/share/classes/java/util/logging/Logger.java
src/share/classes/java/util/logging/Logger.java
+35
-14
test/java/util/logging/AnonLoggerWeakRefLeak.java
test/java/util/logging/AnonLoggerWeakRefLeak.java
+76
-0
test/java/util/logging/AnonLoggerWeakRefLeak.sh
test/java/util/logging/AnonLoggerWeakRefLeak.sh
+246
-0
test/java/util/logging/LoggerWeakRefLeak.java
test/java/util/logging/LoggerWeakRefLeak.java
+89
-0
test/java/util/logging/LoggerWeakRefLeak.sh
test/java/util/logging/LoggerWeakRefLeak.sh
+246
-0
未找到文件。
src/share/classes/java/util/logging/LogManager.java
浏览文件 @
ae7f1139
/*
* Copyright (c) 2000, 20
07
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 20
10
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -29,6 +29,7 @@ package java.util.logging;
import
java.io.*
;
import
java.util.*
;
import
java.security.*
;
import
java.lang.ref.ReferenceQueue
;
import
java.lang.ref.WeakReference
;
import
java.beans.PropertyChangeListener
;
import
java.beans.PropertyChangeSupport
;
...
...
@@ -154,10 +155,10 @@ public class LogManager {
=
new
PropertyChangeSupport
(
LogManager
.
class
);
private
final
static
Level
defaultLevel
=
Level
.
INFO
;
// Table of
known loggers. M
aps names to Loggers.
private
Hashtable
<
String
,
WeakReference
<
Logger
>>
l
oggers
=
new
Hashtable
<
String
,
WeakReference
<
Logger
>
>();
// Tree of
known l
oggers
// Table of
named Loggers that m
aps names to Loggers.
private
Hashtable
<
String
,
LoggerWeakRef
>
namedL
oggers
=
new
Hashtable
<
String
,
LoggerWeakRef
>();
// Tree of
named L
oggers
private
LogNode
root
=
new
LogNode
(
null
);
private
Logger
rootLogger
;
...
...
@@ -417,6 +418,121 @@ public class LogManager {
}});
}
// loggerRefQueue holds LoggerWeakRef objects for Logger objects
// that have been GC'ed.
private
final
ReferenceQueue
<
Logger
>
loggerRefQueue
=
new
ReferenceQueue
<
Logger
>();
// Package-level inner class.
// Helper class for managing WeakReferences to Logger objects.
//
// LogManager.namedLoggers
// - has weak references to all named Loggers
// - namedLoggers keeps the LoggerWeakRef objects for the named
// Loggers around until we can deal with the book keeping for
// the named Logger that is being GC'ed.
// LogManager.LogNode.loggerRef
// - has a weak reference to a named Logger
// - the LogNode will also keep the LoggerWeakRef objects for
// the named Loggers around; currently LogNodes never go away.
// Logger.kids
// - has a weak reference to each direct child Logger; this
// includes anonymous and named Loggers
// - anonymous Loggers are always children of the rootLogger
// which is a strong reference; rootLogger.kids keeps the
// LoggerWeakRef objects for the anonymous Loggers around
// until we can deal with the book keeping.
//
final
class
LoggerWeakRef
extends
WeakReference
<
Logger
>
{
private
String
name
;
// for namedLoggers cleanup
private
LogNode
node
;
// for loggerRef cleanup
private
WeakReference
<
Logger
>
parentRef
;
// for kids cleanup
LoggerWeakRef
(
Logger
logger
)
{
super
(
logger
,
loggerRefQueue
);
name
=
logger
.
getName
();
// save for namedLoggers cleanup
}
// dispose of this LoggerWeakRef object
void
dispose
()
{
if
(
node
!=
null
)
{
// if we have a LogNode, then we were a named Logger
// so clear namedLoggers weak ref to us
manager
.
namedLoggers
.
remove
(
name
);
name
=
null
;
// clear our ref to the Logger's name
node
.
loggerRef
=
null
;
// clear LogNode's weak ref to us
node
=
null
;
// clear our ref to LogNode
}
if
(
parentRef
!=
null
)
{
// this LoggerWeakRef has or had a parent Logger
Logger
parent
=
parentRef
.
get
();
if
(
parent
!=
null
)
{
// the parent Logger is still there so clear the
// parent Logger's weak ref to us
parent
.
removeChildLogger
(
this
);
}
parentRef
=
null
;
// clear our weak ref to the parent Logger
}
}
// set the node field to the specified value
void
setNode
(
LogNode
node
)
{
this
.
node
=
node
;
}
// set the parentRef field to the specified value
void
setParentRef
(
WeakReference
<
Logger
>
parentRef
)
{
this
.
parentRef
=
parentRef
;
}
}
// Package-level method.
// Drain some Logger objects that have been GC'ed.
//
// drainLoggerRefQueueBounded() is called by addLogger() below
// and by Logger.getAnonymousLogger(String) so we'll drain up to
// MAX_ITERATIONS GC'ed Loggers for every Logger we add.
//
// On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives
// us about a 50/50 mix in increased weak ref counts versus
// decreased weak ref counts in the AnonLoggerWeakRefLeak test.
// Here are stats for cleaning up sets of 400 anonymous Loggers:
// - test duration 1 minute
// - sample size of 125 sets of 400
// - average: 1.99 ms
// - minimum: 0.57 ms
// - maximum: 25.3 ms
//
// The same config gives us a better decreased weak ref count
// than increased weak ref count in the LoggerWeakRefLeak test.
// Here are stats for cleaning up sets of 400 named Loggers:
// - test duration 2 minutes
// - sample size of 506 sets of 400
// - average: 0.57 ms
// - minimum: 0.02 ms
// - maximum: 10.9 ms
//
private
final
static
int
MAX_ITERATIONS
=
400
;
final
synchronized
void
drainLoggerRefQueueBounded
()
{
for
(
int
i
=
0
;
i
<
MAX_ITERATIONS
;
i
++)
{
if
(
loggerRefQueue
==
null
)
{
// haven't finished loading LogManager yet
break
;
}
LoggerWeakRef
ref
=
(
LoggerWeakRef
)
loggerRefQueue
.
poll
();
if
(
ref
==
null
)
{
break
;
}
// a Logger object has been GC'ed so clean it up
ref
.
dispose
();
}
}
/**
* Add a named logger. This does nothing and returns false if a logger
* with the same name is already registered.
...
...
@@ -439,13 +555,16 @@ public class LogManager {
throw
new
NullPointerException
();
}
WeakReference
<
Logger
>
ref
=
loggers
.
get
(
name
);
// cleanup some Loggers that have been GC'ed
drainLoggerRefQueueBounded
();
LoggerWeakRef
ref
=
namedLoggers
.
get
(
name
);
if
(
ref
!=
null
)
{
if
(
ref
.
get
()
==
null
)
{
//
Hashtable holds stale weak referenc
e
//
to a logger which has been GC-ed.
//
Allow to register new one
.
l
oggers
.
remove
(
name
);
//
It's possible that the Logger was GC'ed after th
e
//
drainLoggerRefQueueBounded() call above so allow
//
a new one to be registered
.
namedL
oggers
.
remove
(
name
);
}
else
{
// We already have a registered logger with the given name.
return
false
;
...
...
@@ -454,7 +573,8 @@ public class LogManager {
// We're adding a new logger.
// Note that we are creating a weak reference here.
loggers
.
put
(
name
,
new
WeakReference
<
Logger
>(
logger
));
ref
=
new
LoggerWeakRef
(
logger
);
namedLoggers
.
put
(
name
,
ref
);
// Apply any initial level defined for the new logger.
Level
level
=
getLevelProperty
(
name
+
".level"
,
null
);
...
...
@@ -469,11 +589,11 @@ public class LogManager {
// Find the new node and its parent.
LogNode
node
=
findNode
(
name
);
node
.
loggerRef
=
new
WeakReference
<
Logger
>(
logger
)
;
node
.
loggerRef
=
ref
;
Logger
parent
=
null
;
LogNode
nodep
=
node
.
parent
;
while
(
nodep
!=
null
)
{
WeakReference
<
Logger
>
nodeRef
=
nodep
.
loggerRef
;
LoggerWeakRef
nodeRef
=
nodep
.
loggerRef
;
if
(
nodeRef
!=
null
)
{
parent
=
nodeRef
.
get
();
if
(
parent
!=
null
)
{
...
...
@@ -489,6 +609,9 @@ public class LogManager {
// Walk over the children and tell them we are their new parent.
node
.
walkAndSetParent
(
logger
);
// new LogNode is ready so tell the LoggerWeakRef about it
ref
.
setNode
(
node
);
return
true
;
}
...
...
@@ -572,7 +695,7 @@ public class LogManager {
* @return matching logger or null if none is found
*/
public
synchronized
Logger
getLogger
(
String
name
)
{
WeakReference
<
Logger
>
ref
=
l
oggers
.
get
(
name
);
LoggerWeakRef
ref
=
namedL
oggers
.
get
(
name
);
if
(
ref
==
null
)
{
return
null
;
}
...
...
@@ -580,7 +703,7 @@ public class LogManager {
if
(
logger
==
null
)
{
// Hashtable holds stale weak reference
// to a logger which has been GC-ed.
l
oggers
.
remove
(
name
);
namedL
oggers
.
remove
(
name
);
}
return
logger
;
}
...
...
@@ -594,7 +717,7 @@ public class LogManager {
* @return enumeration of logger name strings
*/
public
synchronized
Enumeration
<
String
>
getLoggerNames
()
{
return
l
oggers
.
keys
();
return
namedL
oggers
.
keys
();
}
/**
...
...
@@ -942,7 +1065,7 @@ public class LogManager {
// Nested class to represent a node in our tree of named loggers.
private
static
class
LogNode
{
HashMap
<
String
,
LogNode
>
children
;
WeakReference
<
Logger
>
loggerRef
;
LoggerWeakRef
loggerRef
;
LogNode
parent
;
LogNode
(
LogNode
parent
)
{
...
...
@@ -958,7 +1081,7 @@ public class LogManager {
Iterator
<
LogNode
>
values
=
children
.
values
().
iterator
();
while
(
values
.
hasNext
())
{
LogNode
node
=
values
.
next
();
WeakReference
<
Logger
>
ref
=
node
.
loggerRef
;
LoggerWeakRef
ref
=
node
.
loggerRef
;
Logger
logger
=
(
ref
==
null
)
?
null
:
ref
.
get
();
if
(
logger
==
null
)
{
node
.
walkAndSetParent
(
parent
);
...
...
src/share/classes/java/util/logging/Logger.java
浏览文件 @
ae7f1139
/*
* Copyright (c) 2000, 20
06
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 20
10
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
...
...
@@ -183,7 +183,7 @@ public class Logger {
// We keep weak references from parents to children, but strong
// references from children to parents.
private
volatile
Logger
parent
;
// our nearest parent.
private
ArrayList
<
WeakReference
<
Logger
>
>
kids
;
// WeakReferences to loggers that have us as parent
private
ArrayList
<
LogManager
.
LoggerWeakRef
>
kids
;
// WeakReferences to loggers that have us as parent
private
volatile
Level
levelObject
;
private
volatile
int
levelValue
;
// current effective level value
...
...
@@ -366,13 +366,8 @@ public class Logger {
*
* @return a newly created private Logger
*/
public
static
synchronized
Logger
getAnonymousLogger
()
{
LogManager
manager
=
LogManager
.
getLogManager
();
Logger
result
=
new
Logger
(
null
,
null
);
result
.
anonymous
=
true
;
Logger
root
=
manager
.
getLogger
(
""
);
result
.
doSetParent
(
root
);
return
result
;
public
static
Logger
getAnonymousLogger
()
{
return
getAnonymousLogger
(
null
);
}
/**
...
...
@@ -401,6 +396,8 @@ public class Logger {
*/
public
static
synchronized
Logger
getAnonymousLogger
(
String
resourceBundleName
)
{
LogManager
manager
=
LogManager
.
getLogManager
();
// cleanup some Loggers that have been GC'ed
manager
.
drainLoggerRefQueueBounded
();
Logger
result
=
new
Logger
(
null
,
resourceBundleName
);
result
.
anonymous
=
true
;
Logger
root
=
manager
.
getLogger
(
""
);
...
...
@@ -1380,14 +1377,18 @@ public class Logger {
synchronized
(
treeLock
)
{
// Remove ourself from any previous parent.
LogManager
.
LoggerWeakRef
ref
=
null
;
if
(
parent
!=
null
)
{
// assert parent.kids != null;
for
(
Iterator
<
WeakReference
<
Logger
>
>
iter
=
parent
.
kids
.
iterator
();
iter
.
hasNext
();
)
{
WeakReference
<
Logger
>
ref
=
iter
.
next
();
for
(
Iterator
<
LogManager
.
LoggerWeakRef
>
iter
=
parent
.
kids
.
iterator
();
iter
.
hasNext
();
)
{
ref
=
iter
.
next
();
Logger
kid
=
ref
.
get
();
if
(
kid
==
this
)
{
// ref is used down below to complete the reparenting
iter
.
remove
();
break
;
}
else
{
ref
=
null
;
}
}
// We have now removed ourself from our parents' kids.
...
...
@@ -1396,9 +1397,14 @@ public class Logger {
// Set our new parent.
parent
=
newParent
;
if
(
parent
.
kids
==
null
)
{
parent
.
kids
=
new
ArrayList
<
WeakReference
<
Logger
>>(
2
);
parent
.
kids
=
new
ArrayList
<
LogManager
.
LoggerWeakRef
>(
2
);
}
if
(
ref
==
null
)
{
// we didn't have a previous parent
ref
=
manager
.
new
LoggerWeakRef
(
this
);
}
parent
.
kids
.
add
(
new
WeakReference
<
Logger
>(
this
));
ref
.
setParentRef
(
new
WeakReference
<
Logger
>(
parent
));
parent
.
kids
.
add
(
ref
);
// As a result of the reparenting, the effective level
// may have changed for us and our children.
...
...
@@ -1407,6 +1413,21 @@ public class Logger {
}
}
// Package-level method.
// Remove the weak reference for the specified child Logger from the
// kid list. We should only be called from LoggerWeakRef.dispose().
final
void
removeChildLogger
(
LogManager
.
LoggerWeakRef
child
)
{
synchronized
(
treeLock
)
{
for
(
Iterator
<
LogManager
.
LoggerWeakRef
>
iter
=
kids
.
iterator
();
iter
.
hasNext
();
)
{
LogManager
.
LoggerWeakRef
ref
=
iter
.
next
();
if
(
ref
==
child
)
{
iter
.
remove
();
return
;
}
}
}
}
// Recalculate the effective level for this node and
// recursively for our children.
...
...
@@ -1438,7 +1459,7 @@ public class Logger {
// Recursively update the level on each of our kids.
if
(
kids
!=
null
)
{
for
(
int
i
=
0
;
i
<
kids
.
size
();
i
++)
{
WeakReference
<
Logger
>
ref
=
kids
.
get
(
i
);
LogManager
.
LoggerWeakRef
ref
=
kids
.
get
(
i
);
Logger
kid
=
ref
.
get
();
if
(
kid
!=
null
)
{
kid
.
updateEffectiveLevel
();
...
...
test/java/util/logging/AnonLoggerWeakRefLeak.java
0 → 100644
浏览文件 @
ae7f1139
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import
java.util.logging.*
;
public
class
AnonLoggerWeakRefLeak
{
public
static
int
DEFAULT_LOOP_TIME
=
60
;
// time is in seconds
public
static
void
main
(
String
[]
args
)
{
int
loop_time
=
0
;
int
max_loop_time
=
DEFAULT_LOOP_TIME
;
if
(
args
.
length
==
0
)
{
System
.
out
.
println
(
"INFO: using default time of "
+
max_loop_time
+
" seconds."
);
}
else
{
try
{
max_loop_time
=
Integer
.
parseInt
(
args
[
0
]);
}
catch
(
NumberFormatException
nfe
)
{
System
.
err
.
println
(
"Error: '"
+
args
[
0
]
+
"': is not a valid seconds value."
);
System
.
err
.
println
(
"Usage: AnonLoggerWeakRefLeak [seconds]"
);
System
.
exit
(
1
);
}
}
long
count
=
0
;
long
now
=
0
;
long
startTime
=
System
.
currentTimeMillis
();
while
(
now
<
(
startTime
+
(
max_loop_time
*
1000
)))
{
if
((
count
%
1000
)
==
0
)
{
// Print initial call count to let caller know that
// we're up and running and then periodically
System
.
out
.
println
(
"INFO: call count = "
+
count
);
}
for
(
int
i
=
0
;
i
<
100
;
i
++)
{
// this Logger call is leaking a WeakReference in Logger.kids
java
.
util
.
logging
.
Logger
.
getAnonymousLogger
();
count
++;
}
try
{
// delay for 1/10 of a second to avoid CPU saturation
Thread
.
sleep
(
100
);
}
catch
(
InterruptedException
ie
)
{
// ignore any exceptions
}
now
=
System
.
currentTimeMillis
();
}
System
.
out
.
println
(
"INFO: final loop count = "
+
count
);
}
}
test/java/util/logging/AnonLoggerWeakRefLeak.sh
0 → 100644
浏览文件 @
ae7f1139
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# @test
# @bug 6942989
# @summary Check for WeakReference leak in anonymous Logger objects
# @author Daniel D. Daugherty
#
# @run build AnonLoggerWeakRefLeak
# @run shell/timeout=180 AnonLoggerWeakRefLeak.sh
# The timeout is: 2 minutes for infrastructure and 1 minute for the test
#
if
[
"
${
TESTJAVA
}
"
=
""
]
then
echo
"TESTJAVA not set. Test cannot execute. Failed."
exit
1
fi
if
[
"
${
TESTSRC
}
"
=
""
]
then
echo
"TESTSRC not set. Test cannot execute. Failed."
exit
1
fi
if
[
"
${
TESTCLASSES
}
"
=
""
]
then
echo
"TESTCLASSES not set. Test cannot execute. Failed."
exit
1
fi
JAVA
=
"
${
TESTJAVA
}
"
/bin/java
JMAP
=
"
${
TESTJAVA
}
"
/bin/jmap
JPS
=
"
${
TESTJAVA
}
"
/bin/jps
set
-eu
TEST_NAME
=
"AnonLoggerWeakRefLeak"
TARGET_CLASS
=
"java
\.
lang
\.
ref
\.
WeakReference"
is_cygwin
=
false
is_mks
=
false
is_windows
=
false
case
`
uname
-s
`
in
CYGWIN
*
)
is_cygwin
=
true
is_windows
=
true
;;
Windows_
*
)
is_mks
=
true
is_windows
=
true
;;
*
)
;;
esac
# wrapper for grep
#
grep_cmd
()
{
set
+e
if
$is_windows
;
then
# need dos2unix to get rid of CTRL-M chars from java output
dos2unix |
grep
"
$@
"
status
=
"
$?
"
else
grep
"
$@
"
status
=
"
$?
"
fi
set
-e
}
# MAIN begins here
#
seconds
=
if
[
"$#"
-gt
0
]
;
then
seconds
=
"
$1
"
fi
# see if this version of jmap supports the '-histo:live' option
jmap_option
=
"-histo:live"
set
+e
"
${
JMAP
}
"
"
$jmap_option
"
0
>
"
$TEST_NAME
.jmap"
2>&1
grep
'^Usage: '
"
$TEST_NAME
.jmap"
>
/dev/null 2>&1
status
=
"
$?
"
set
-e
if
[
"
$status
"
=
0
]
;
then
echo
"INFO: switching jmap option from '
$jmap_option
'
\c
"
jmap_option
=
"-histo"
echo
" to '
$jmap_option
'."
fi
"
${
JAVA
}
"
${
TESTVMOPTS
}
-classpath
"
${
TESTCLASSES
}
"
\
"
$TEST_NAME
"
$seconds
>
"
$TEST_NAME
.log"
2>&1 &
test_pid
=
"
$!
"
echo
"INFO: starting
$TEST_NAME
as pid =
$test_pid
"
# wait for test program to get going
count
=
0
while
[
"
$count
"
-lt
30
]
;
do
sleep
2
grep_cmd
'^INFO: call count = 0$'
<
"
$TEST_NAME
.log"
>
/dev/null 2>&1
if
[
"
$status
"
=
0
]
;
then
break
fi
count
=
`
expr
$count
+ 1
`
done
if
[
"
$count
"
-ge
30
]
;
then
echo
"ERROR:
$TEST_NAME
failed to get going."
>
&2
echo
"INFO: killing
$test_pid
"
kill
"
$test_pid
"
exit
1
elif
[
"
$count
"
-gt
1
]
;
then
echo
"INFO:
$TEST_NAME
took
$count
loops to start."
fi
if
$is_cygwin
;
then
# We need the Windows pid for jmap and not the Cygwin pid.
# Note: '\t' works on Cygwin, but doesn't seem to work on Solaris.
jmap_pid
=
`
"
${
JPS
}
"
| grep_cmd
"[
\t
]
$TEST_NAME
$"
|
sed
's/[ \t].*//'
`
if
[
-z
"
$jmap_pid
"
]
;
then
echo
"FAIL: jps could not map Cygwin pid to Windows pid."
>
&2
echo
"INFO: killing
$test_pid
"
kill
"
$test_pid
"
exit
2
fi
echo
"INFO: pid =
$test_pid
maps to Windows pid =
$jmap_pid
"
else
jmap_pid
=
"
$test_pid
"
fi
decreasing_cnt
=
0
increasing_cnt
=
0
loop_cnt
=
0
prev_instance_cnt
=
0
while
true
;
do
# Output format for 'jmap -histo' in JDK1.5.0:
#
# <#bytes> <#instances> <class_name>
#
# Output format for 'jmap -histo:live':
#
# <num>: <#instances> <#bytes> <class_name>
#
set
+e
"
${
JMAP
}
"
"
$jmap_option
"
"
$jmap_pid
"
>
"
$TEST_NAME
.jmap"
2>&1
status
=
"
$?
"
set
-e
if
[
"
$status
"
!=
0
]
;
then
echo
"INFO: jmap exited with exit code =
$status
"
if
[
"
$loop_cnt
"
=
0
]
;
then
echo
"INFO: on the first iteration so no samples were taken."
echo
"INFO: start of jmap output:"
cat
"
$TEST_NAME
.jmap"
echo
"INFO: end of jmap output."
echo
"FAIL: jmap is unable to take any samples."
>
&2
echo
"INFO: killing
$test_pid
"
kill
"
$test_pid
"
exit
2
fi
echo
"INFO: The likely reason is that
$TEST_NAME
has finished running."
break
fi
instance_cnt
=
`
grep_cmd
"[ ]
$TARGET_CLASS
$"
\
<
"
$TEST_NAME
.jmap"
\
|
sed
'
# strip leading whitespace; does nothing in JDK1.5.0
s/^[ ][ ]*//
# strip <#bytes> in JDK1.5.0; does nothing otherwise
s/^[1-9][0-9]*[ ][ ]*//
# strip <num>: field; does nothing in JDK1.5.0
s/^[1-9][0-9]*:[ ][ ]*//
# strip <class_name> field
s/[ ].*//
'
`
if
[
-z
"
$instance_cnt
"
]
;
then
echo
"INFO: instance count is unexpectedly empty"
if
[
"
$loop_cnt
"
=
0
]
;
then
echo
"INFO: on the first iteration so no sample was found."
echo
"INFO: There is likely a problem with the sed filter."
echo
"INFO: start of jmap output:"
cat
"
$TEST_NAME
.jmap"
echo
"INFO: end of jmap output."
echo
"FAIL: cannot find the instance count value."
>
&2
echo
"INFO: killing
$test_pid
"
kill
"
$test_pid
"
exit
2
fi
else
echo
"INFO: instance_cnt =
$instance_cnt
"
if
[
"
$instance_cnt
"
-gt
"
$prev_instance_cnt
"
]
;
then
increasing_cnt
=
`
expr
$increasing_cnt
+ 1
`
else
decreasing_cnt
=
`
expr
$decreasing_cnt
+ 1
`
fi
prev_instance_cnt
=
"
$instance_cnt
"
fi
# delay between samples
sleep
5
loop_cnt
=
`
expr
$loop_cnt
+ 1
`
done
echo
"INFO: increasing_cnt =
$increasing_cnt
"
echo
"INFO: decreasing_cnt =
$decreasing_cnt
"
echo
"INFO: The instance count of"
`
eval echo
$TARGET_CLASS
`
"objects"
if
[
"
$decreasing_cnt
"
=
0
]
;
then
echo
"INFO: is always increasing."
echo
"FAIL: This indicates that there is a memory leak."
>
&2
exit
2
fi
echo
"INFO: is both increasing and decreasing."
echo
"PASS: This indicates that there is not a memory leak."
exit
0
test/java/util/logging/LoggerWeakRefLeak.java
0 → 100644
浏览文件 @
ae7f1139
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import
java.util.logging.*
;
public
class
LoggerWeakRefLeak
{
// AnonLoggerWeakRefLeak checks for one weak reference leak.
// LoggerWeakRefLeak checks for two weak reference leaks so
// this test runs twice as long, by default.
public
static
int
DEFAULT_LOOP_TIME
=
120
;
// time is in seconds
public
static
void
main
(
String
[]
args
)
{
int
loop_time
=
0
;
int
max_loop_time
=
DEFAULT_LOOP_TIME
;
if
(
args
.
length
==
0
)
{
System
.
out
.
println
(
"INFO: using default time of "
+
max_loop_time
+
" seconds."
);
}
else
{
try
{
max_loop_time
=
Integer
.
parseInt
(
args
[
0
]);
}
catch
(
NumberFormatException
nfe
)
{
System
.
err
.
println
(
"Error: '"
+
args
[
0
]
+
"': is not a valid seconds value."
);
System
.
err
.
println
(
"Usage: LoggerWeakRefLeak [seconds]"
);
System
.
exit
(
1
);
}
}
long
count
=
0
;
int
loggerCount
=
0
;
long
now
=
0
;
long
startTime
=
System
.
currentTimeMillis
();
while
(
now
<
(
startTime
+
(
max_loop_time
*
1000
)))
{
if
((
count
%
1000
)
==
0
)
{
// Print initial call count to let caller know that
// we're up and running and then periodically
System
.
out
.
println
(
"INFO: call count = "
+
count
);
}
for
(
int
i
=
0
;
i
<
100
;
i
++)
{
// This Logger call is leaking two different WeakReferences:
// - one in LogManager.LogNode
// - one in Logger.kids
java
.
util
.
logging
.
Logger
.
getLogger
(
"logger-"
+
loggerCount
);
count
++;
if
(++
loggerCount
>=
25000
)
{
// Limit the Logger namespace used by the test so
// the weak refs in LogManager.loggers that are
// being properly managed don't skew the counts
// by too much.
loggerCount
=
0
;
}
}
try
{
// delay for 1/10 of a second to avoid CPU saturation
Thread
.
sleep
(
100
);
}
catch
(
InterruptedException
ie
)
{
// ignore any exceptions
}
now
=
System
.
currentTimeMillis
();
}
System
.
out
.
println
(
"INFO: final loop count = "
+
count
);
}
}
test/java/util/logging/LoggerWeakRefLeak.sh
0 → 100644
浏览文件 @
ae7f1139
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# @test
# @bug 6942989
# @summary Check for WeakReference leak in Logger objects
# @author Daniel D. Daugherty
#
# @run build LoggerWeakRefLeak
# @run shell/timeout=240 LoggerWeakRefLeak.sh
# The timeout is: 2 minutes for infrastructure and 1 minute for the test
#
if
[
"
${
TESTJAVA
}
"
=
""
]
then
echo
"TESTJAVA not set. Test cannot execute. Failed."
exit
1
fi
if
[
"
${
TESTSRC
}
"
=
""
]
then
echo
"TESTSRC not set. Test cannot execute. Failed."
exit
1
fi
if
[
"
${
TESTCLASSES
}
"
=
""
]
then
echo
"TESTCLASSES not set. Test cannot execute. Failed."
exit
1
fi
JAVA
=
"
${
TESTJAVA
}
"
/bin/java
JMAP
=
"
${
TESTJAVA
}
"
/bin/jmap
JPS
=
"
${
TESTJAVA
}
"
/bin/jps
set
-eu
TEST_NAME
=
"LoggerWeakRefLeak"
TARGET_CLASS
=
"java
\.
lang
\.
ref
\.
WeakReference"
is_cygwin
=
false
is_mks
=
false
is_windows
=
false
case
`
uname
-s
`
in
CYGWIN
*
)
is_cygwin
=
true
is_windows
=
true
;;
Windows_
*
)
is_mks
=
true
is_windows
=
true
;;
*
)
;;
esac
# wrapper for grep
#
grep_cmd
()
{
set
+e
if
$is_windows
;
then
# need dos2unix to get rid of CTRL-M chars from java output
dos2unix |
grep
"
$@
"
status
=
"
$?
"
else
grep
"
$@
"
status
=
"
$?
"
fi
set
-e
}
# MAIN begins here
#
seconds
=
if
[
"$#"
-gt
0
]
;
then
seconds
=
"
$1
"
fi
# see if this version of jmap supports the '-histo:live' option
jmap_option
=
"-histo:live"
set
+e
"
${
JMAP
}
"
"
$jmap_option
"
0
>
"
$TEST_NAME
.jmap"
2>&1
grep
'^Usage: '
"
$TEST_NAME
.jmap"
>
/dev/null 2>&1
status
=
"
$?
"
set
-e
if
[
"
$status
"
=
0
]
;
then
echo
"INFO: switching jmap option from '
$jmap_option
'
\c
"
jmap_option
=
"-histo"
echo
" to '
$jmap_option
'."
fi
"
${
JAVA
}
"
${
TESTVMOPTS
}
-classpath
"
${
TESTCLASSES
}
"
\
"
$TEST_NAME
"
$seconds
>
"
$TEST_NAME
.log"
2>&1 &
test_pid
=
"
$!
"
echo
"INFO: starting
$TEST_NAME
as pid =
$test_pid
"
# wait for test program to get going
count
=
0
while
[
"
$count
"
-lt
30
]
;
do
sleep
2
grep_cmd
'^INFO: call count = 0$'
<
"
$TEST_NAME
.log"
>
/dev/null 2>&1
if
[
"
$status
"
=
0
]
;
then
break
fi
count
=
`
expr
$count
+ 1
`
done
if
[
"
$count
"
-ge
30
]
;
then
echo
"ERROR:
$TEST_NAME
failed to get going."
>
&2
echo
"INFO: killing
$test_pid
"
kill
"
$test_pid
"
exit
1
elif
[
"
$count
"
-gt
1
]
;
then
echo
"INFO:
$TEST_NAME
took
$count
loops to start."
fi
if
$is_cygwin
;
then
# We need the Windows pid for jmap and not the Cygwin pid.
# Note: '\t' works on Cygwin, but doesn't seem to work on Solaris.
jmap_pid
=
`
"
${
JPS
}
"
| grep_cmd
"[
\t
]
$TEST_NAME
$"
|
sed
's/[ \t].*//'
`
if
[
-z
"
$jmap_pid
"
]
;
then
echo
"FAIL: jps could not map Cygwin pid to Windows pid."
>
&2
echo
"INFO: killing
$test_pid
"
kill
"
$test_pid
"
exit
2
fi
echo
"INFO: pid =
$test_pid
maps to Windows pid =
$jmap_pid
"
else
jmap_pid
=
"
$test_pid
"
fi
decreasing_cnt
=
0
increasing_cnt
=
0
loop_cnt
=
0
prev_instance_cnt
=
0
while
true
;
do
# Output format for 'jmap -histo' in JDK1.5.0:
#
# <#bytes> <#instances> <class_name>
#
# Output format for 'jmap -histo:live':
#
# <num>: <#instances> <#bytes> <class_name>
#
set
+e
"
${
JMAP
}
"
"
$jmap_option
"
"
$jmap_pid
"
>
"
$TEST_NAME
.jmap"
2>&1
status
=
"
$?
"
set
-e
if
[
"
$status
"
!=
0
]
;
then
echo
"INFO: jmap exited with exit code =
$status
"
if
[
"
$loop_cnt
"
=
0
]
;
then
echo
"INFO: on the first iteration so no samples were taken."
echo
"INFO: start of jmap output:"
cat
"
$TEST_NAME
.jmap"
echo
"INFO: end of jmap output."
echo
"FAIL: jmap is unable to take any samples."
>
&2
echo
"INFO: killing
$test_pid
"
kill
"
$test_pid
"
exit
2
fi
echo
"INFO: The likely reason is that
$TEST_NAME
has finished running."
break
fi
instance_cnt
=
`
grep_cmd
"[ ]
$TARGET_CLASS
$"
\
<
"
$TEST_NAME
.jmap"
\
|
sed
'
# strip leading whitespace; does nothing in JDK1.5.0
s/^[ ][ ]*//
# strip <#bytes> in JDK1.5.0; does nothing otherwise
s/^[1-9][0-9]*[ ][ ]*//
# strip <num>: field; does nothing in JDK1.5.0
s/^[1-9][0-9]*:[ ][ ]*//
# strip <class_name> field
s/[ ].*//
'
`
if
[
-z
"
$instance_cnt
"
]
;
then
echo
"INFO: instance count is unexpectedly empty"
if
[
"
$loop_cnt
"
=
0
]
;
then
echo
"INFO: on the first iteration so no sample was found."
echo
"INFO: There is likely a problem with the sed filter."
echo
"INFO: start of jmap output:"
cat
"
$TEST_NAME
.jmap"
echo
"INFO: end of jmap output."
echo
"FAIL: cannot find the instance count value."
>
&2
echo
"INFO: killing
$test_pid
"
kill
"
$test_pid
"
exit
2
fi
else
echo
"INFO: instance_cnt =
$instance_cnt
"
if
[
"
$instance_cnt
"
-gt
"
$prev_instance_cnt
"
]
;
then
increasing_cnt
=
`
expr
$increasing_cnt
+ 1
`
else
decreasing_cnt
=
`
expr
$decreasing_cnt
+ 1
`
fi
prev_instance_cnt
=
"
$instance_cnt
"
fi
# delay between samples
sleep
5
loop_cnt
=
`
expr
$loop_cnt
+ 1
`
done
echo
"INFO: increasing_cnt =
$increasing_cnt
"
echo
"INFO: decreasing_cnt =
$decreasing_cnt
"
echo
"INFO: The instance count of"
`
eval echo
$TARGET_CLASS
`
"objects"
if
[
"
$decreasing_cnt
"
=
0
]
;
then
echo
"INFO: is always increasing."
echo
"FAIL: This indicates that there is a memory leak."
>
&2
exit
2
fi
echo
"INFO: is both increasing and decreasing."
echo
"PASS: This indicates that there is not a memory leak."
exit
0
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录