1 #
   2 # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
   3 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4 #
   5 # This code is free software; you can redistribute it and/or modify it
   6 # under the terms of the GNU General Public License version 2 only, as
   7 # published by the Free Software Foundation.
   8 #
   9 # This code is distributed in the hope that it will be useful, but WITHOUT
  10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12 # version 2 for more details (a copy is included in the LICENSE file that
  13 # accompanied this code).
  14 #
  15 # You should have received a copy of the GNU General Public License version
  16 # 2 along with this work; if not, write to the Free Software Foundation,
  17 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18 #
  19 # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20 # or visit www.oracle.com if you need additional information or have any
  21 # questions.
  22 #
  23 
  24 # @test
  25 # @bug 6942989
  26 # @summary Check for WeakReference leak in Logger objects
  27 # @author Daniel D. Daugherty
  28 #
  29 # @run build LoggerWeakRefLeak
  30 # @run shell/timeout=240 LoggerWeakRefLeak.sh
  31 
  32 # The timeout is: 2 minutes for infrastructure and 1 minute for the test
  33 #
  34 
  35 if [ "${TESTJAVA}" = "" ]
  36 then
  37   echo "TESTJAVA not set.  Test cannot execute.  Failed."
  38   exit 1
  39 fi
  40 
  41 if [ "${TESTSRC}" = "" ]
  42 then
  43   echo "TESTSRC not set.  Test cannot execute.  Failed."
  44   exit 1
  45 fi
  46 
  47 if [ "${TESTCLASSES}" = "" ]
  48 then
  49   echo "TESTCLASSES not set.  Test cannot execute.  Failed."
  50   exit 1
  51 fi
  52 
  53 JAVA="${TESTJAVA}"/bin/java
  54 JMAP="${TESTJAVA}"/bin/jmap
  55 JPS="${TESTJAVA}"/bin/jps
  56 
  57 set -eu
  58 
  59 TEST_NAME="LoggerWeakRefLeak"
  60 TARGET_CLASS="java\.lang\.ref\.WeakReference"
  61 
  62 is_cygwin=false
  63 is_mks=false
  64 is_windows=false
  65 
  66 case `uname -s` in
  67 CYGWIN*)
  68     is_cygwin=true
  69     is_windows=true
  70     ;;
  71 Windows_*)
  72     is_mks=true
  73     is_windows=true
  74     ;;
  75 *)
  76     ;;
  77 esac
  78 
  79 
  80 # wrapper for grep
  81 #
  82 grep_cmd() {
  83     set +e
  84     if $is_windows; then
  85         # need dos2unix to get rid of CTRL-M chars from java output
  86         dos2unix | grep "$@"
  87         status="$?"
  88     else
  89         grep "$@"
  90         status="$?"
  91     fi
  92     set -e
  93 }
  94 
  95 
  96 # MAIN begins here
  97 #
  98 
  99 seconds=
 100 if [ "$#" -gt 0 ]; then
 101     seconds="$1"
 102 fi
 103 
 104 # see if this version of jmap supports the '-histo:live' option
 105 jmap_option="-histo:live"
 106 set +e
 107 "${JMAP}" "$jmap_option" 0 > "$TEST_NAME.jmap" 2>&1
 108 grep '^Usage: ' "$TEST_NAME.jmap" > /dev/null 2>&1
 109 status="$?"
 110 set -e
 111 if [ "$status" = 0 ]; then
 112     echo "INFO: switching jmap option from '$jmap_option'\c"
 113     jmap_option="-histo"
 114     echo " to '$jmap_option'."
 115 fi
 116 
 117 "${JAVA}" ${TESTVMOPTS} -classpath "${TESTCLASSES}" \
 118     "$TEST_NAME" $seconds > "$TEST_NAME.log" 2>&1 &
 119 test_pid="$!"
 120 echo "INFO: starting $TEST_NAME as pid = $test_pid"
 121 
 122 # wait for test program to get going
 123 count=0
 124 while [ "$count" -lt 30 ]; do
 125     sleep 2
 126     grep_cmd '^INFO: call count = 0$' < "$TEST_NAME.log" > /dev/null 2>&1
 127     if [ "$status" = 0 ]; then
 128         break
 129     fi
 130     count=`expr $count + 1`
 131 done
 132 
 133 if [ "$count" -ge 30 ]; then
 134     echo "ERROR: $TEST_NAME failed to get going." >&2
 135     echo "INFO: killing $test_pid"
 136     kill "$test_pid"
 137     exit 1
 138 elif [ "$count" -gt 1 ]; then
 139     echo "INFO: $TEST_NAME took $count loops to start."
 140 fi
 141 
 142 if $is_cygwin; then
 143     # We need the Windows pid for jmap and not the Cygwin pid.
 144     # Note: '\t' works on Cygwin, but doesn't seem to work on Solaris.
 145     jmap_pid=`"${JPS}"| grep_cmd "[ \t]$TEST_NAME$" | sed 's/[ \t].*//'`
 146     if [ -z "$jmap_pid" ]; then
 147         echo "FAIL: jps could not map Cygwin pid to Windows pid." >&2
 148         echo "INFO: killing $test_pid"
 149         kill "$test_pid"
 150         exit 2
 151     fi
 152     echo "INFO: pid = $test_pid maps to Windows pid = $jmap_pid"
 153 else
 154     jmap_pid="$test_pid"
 155 fi
 156 
 157 decreasing_cnt=0
 158 increasing_cnt=0
 159 loop_cnt=0
 160 prev_instance_cnt=0
 161 
 162 while true; do
 163     # Output format for 'jmap -histo' in JDK1.5.0:
 164     #
 165     #     <#bytes> <#instances> <class_name>
 166     #
 167     # Output format for 'jmap -histo:live':
 168     #
 169     #     <num>: <#instances> <#bytes> <class_name>
 170     #
 171     set +e
 172     "${JMAP}" "$jmap_option" "$jmap_pid" > "$TEST_NAME.jmap" 2>&1
 173     status="$?"
 174     set -e
 175 
 176     if [ "$status" != 0 ]; then
 177         echo "INFO: jmap exited with exit code = $status"
 178         if [ "$loop_cnt" = 0 ]; then
 179             echo "INFO: on the first iteration so no samples were taken."
 180             echo "INFO: start of jmap output:"
 181             cat "$TEST_NAME.jmap"
 182             echo "INFO: end of jmap output."
 183             echo "FAIL: jmap is unable to take any samples." >&2
 184             echo "INFO: killing $test_pid"
 185             kill "$test_pid"
 186             exit 2
 187         fi
 188         echo "INFO: The likely reason is that $TEST_NAME has finished running."
 189         break
 190     fi
 191 
 192     instance_cnt=`grep_cmd "[   ]$TARGET_CLASS$" \
 193         < "$TEST_NAME.jmap" \
 194         | sed '
 195             # strip leading whitespace; does nothing in JDK1.5.0
 196             s/^[        ][      ]*//
 197             # strip <#bytes> in JDK1.5.0; does nothing otherwise
 198             s/^[1-9][0-9]*[     ][      ]*//
 199             # strip <num>: field; does nothing in JDK1.5.0
 200             s/^[1-9][0-9]*:[    ][      ]*//
 201             # strip <class_name> field
 202             s/[         ].*//
 203             '`
 204     if [ -z "$instance_cnt" ]; then
 205         echo "INFO: instance count is unexpectedly empty"
 206         if [ "$loop_cnt" = 0 ]; then
 207             echo "INFO: on the first iteration so no sample was found."
 208             echo "INFO: There is likely a problem with the sed filter."
 209             echo "INFO: start of jmap output:"
 210             cat "$TEST_NAME.jmap"
 211             echo "INFO: end of jmap output."
 212             echo "FAIL: cannot find the instance count value." >&2
 213             echo "INFO: killing $test_pid"
 214             kill "$test_pid"
 215             exit 2
 216         fi
 217     else
 218         echo "INFO: instance_cnt = $instance_cnt"
 219 
 220         if [ "$instance_cnt" -gt "$prev_instance_cnt" ]; then
 221             increasing_cnt=`expr $increasing_cnt + 1`
 222         else
 223             decreasing_cnt=`expr $decreasing_cnt + 1`
 224         fi
 225         prev_instance_cnt="$instance_cnt"
 226     fi
 227 
 228     # delay between samples
 229     sleep 5
 230 
 231     loop_cnt=`expr $loop_cnt + 1`
 232 done
 233 
 234 echo "INFO: increasing_cnt = $increasing_cnt"
 235 echo "INFO: decreasing_cnt = $decreasing_cnt"
 236 
 237 echo "INFO: The instance count of" `eval echo $TARGET_CLASS` "objects"
 238 if [ "$decreasing_cnt" = 0 ]; then
 239     echo "INFO: is always increasing."
 240     echo "FAIL: This indicates that there is a memory leak." >&2
 241     exit 2
 242 fi
 243 
 244 echo "INFO: is both increasing and decreasing."
 245 echo "PASS: This indicates that there is not a memory leak."
 246 exit 0