001
014
015 package com.liferay.portal.kernel.util;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.process.ProcessUtil;
020
021 import java.lang.management.ManagementFactory;
022 import java.lang.management.RuntimeMXBean;
023
024 import java.util.ArrayList;
025 import java.util.List;
026 import java.util.concurrent.Future;
027
028
031 public class HeapUtil {
032
033 public static int getProcessId() {
034 if (!_SUPPORTED) {
035 throw new IllegalStateException(
036 HeapUtil.class.getName() + " does not support the current JVM");
037 }
038
039 return _PROCESS_ID;
040 }
041
042 public static Future<ObjectValuePair<Void, Void>> heapDump(
043 boolean live, boolean binary, String file) {
044
045 return heapDump(_PROCESS_ID, live, binary, file);
046 }
047
048 public static Future<ObjectValuePair<Void, Void>> heapDump(
049 int processId, boolean live, boolean binary, String file) {
050
051 if (!_SUPPORTED) {
052 throw new IllegalStateException(
053 HeapUtil.class.getName() + " does not support the current JVM");
054 }
055
056 StringBundler sb = new StringBundler(5);
057
058 sb.append("-dump:");
059
060 if (live) {
061 sb.append("live,");
062 }
063
064 if (binary) {
065 sb.append("format=b,");
066 }
067
068 sb.append("file=");
069 sb.append(file);
070
071 List<String> arguments = new ArrayList<String>();
072
073 arguments.add("jmap");
074 arguments.add(sb.toString());
075 arguments.add(String.valueOf(processId));
076
077 try {
078 return ProcessUtil.execute(
079 ProcessUtil.LOGGING_OUTPUT_PROCESSOR, arguments);
080 }
081 catch (Exception e) {
082 throw new RuntimeException("Unable to perform heap dump", e);
083 }
084 }
085
086 public static boolean isSupported() {
087 return _SUPPORTED;
088 }
089
090 private static void _checkJMap(int processId) throws Exception {
091 Future<ObjectValuePair<byte[], byte[]>> future =
092 ProcessUtil.execute(
093 ProcessUtil.COLLECTOR_OUTPUT_PROCESSOR, "jmap", "-histo:live",
094 String.valueOf(processId));
095
096 ObjectValuePair<byte[], byte[]> objectValuePair = future.get();
097
098 String stdOutString = new String(objectValuePair.getKey());
099
100 if (!stdOutString.contains("#instances")) {
101 throw new IllegalStateException(
102 "JMap cannot connect to process ID " + processId);
103 }
104
105 byte[] stdErrBytes = objectValuePair.getValue();
106
107 if (stdErrBytes.length != 0) {
108 throw new IllegalStateException(
109 "JMap returns with error: " + new String(stdErrBytes));
110 }
111 }
112
113 private static void _checkJPS(int processId) throws Exception {
114 Future<ObjectValuePair<byte[], byte[]>> future = ProcessUtil.execute(
115 ProcessUtil.COLLECTOR_OUTPUT_PROCESSOR, "jps");
116
117 ObjectValuePair<byte[], byte[]> objectValuePair = future.get();
118
119 String stdOutString = new String(objectValuePair.getKey());
120
121 if (!stdOutString.contains(String.valueOf(processId))) {
122 throw new IllegalStateException(
123 "JPS cannot detect expected process ID " + processId);
124 }
125
126 byte[] stdErrBytes = objectValuePair.getValue();
127
128 if (stdErrBytes.length != 0) {
129 throw new IllegalStateException(
130 "JPS returns with error: " + new String(stdErrBytes));
131 }
132 }
133
134 private static int _getProcessId() {
135 RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
136
137 String name = runtimeMXBean.getName();
138
139 int index = name.indexOf(CharPool.AT);
140
141 if (index == -1) {
142 throw new RuntimeException("Unable to parse process name " + name);
143 }
144
145 int pid = GetterUtil.getInteger(name.substring(0, index));
146
147 if (pid == 0) {
148 throw new RuntimeException("Unable to parse process name " + name);
149 }
150
151 return pid;
152 }
153
154 private static final int _PROCESS_ID;
155
156 private static final boolean _SUPPORTED;
157
158 private static final Log _log = LogFactoryUtil.getLog(HeapUtil.class);
159
160 static {
161 int processId = -1;
162 boolean supported = false;
163
164 if (JavaDetector.isOracle()) {
165 try {
166 processId = _getProcessId();
167
168 _checkJPS(processId);
169 _checkJMap(processId);
170
171 supported = true;
172 }
173 catch (Exception e) {
174 if (_log.isWarnEnabled()) {
175 _log.warn(HeapUtil.class.getName() + " is disabled", e);
176 }
177 }
178 }
179 else if (_log.isDebugEnabled()) {
180 _log.debug(
181 HeapUtil.class.getName() + " is only supported on Oracle JVMs");
182 }
183
184 _PROCESS_ID = processId;
185 _SUPPORTED = supported;
186 }
187
188 }