PageRenderTime 61ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/test/074-gc-thrash/src/Main.java

https://gitlab.com/Atomic-ROM/art
Java | 359 lines | 235 code | 57 blank | 67 comment | 30 complexity | 1f4913f6e96a9770083193cc51af7ed2 MD5 | raw file
  1. /*
  2. * Copyright (C) 2009 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import java.io.File;
  17. import java.lang.ref.WeakReference;
  18. import java.lang.reflect.Method;
  19. import java.lang.reflect.InvocationTargetException;
  20. public class Main {
  21. public static volatile boolean quit = false;
  22. public static final boolean DEBUG = false;
  23. private static final boolean WRITE_HPROF_DATA = false;
  24. private static final int TEST_TIME = 10;
  25. private static final String OUTPUT_FILE = "gc-thrash.hprof";
  26. public static void main(String[] args) {
  27. // dump heap before
  28. System.out.println("Running (" + TEST_TIME + " seconds) ...");
  29. runTests();
  30. Method dumpHprofDataMethod = null;
  31. String dumpFile = null;
  32. if (WRITE_HPROF_DATA) {
  33. dumpHprofDataMethod = getDumpHprofDataMethod();
  34. if (dumpHprofDataMethod != null) {
  35. dumpFile = getDumpFileName();
  36. System.out.println("Sending output to " + dumpFile);
  37. }
  38. }
  39. System.gc();
  40. System.runFinalization();
  41. System.gc();
  42. if (WRITE_HPROF_DATA && dumpHprofDataMethod != null) {
  43. try {
  44. dumpHprofDataMethod.invoke(null, dumpFile);
  45. } catch (IllegalAccessException iae) {
  46. System.err.println(iae);
  47. } catch (InvocationTargetException ite) {
  48. System.err.println(ite);
  49. }
  50. }
  51. System.out.println("Done.");
  52. }
  53. /**
  54. * Finds VMDebug.dumpHprofData() through reflection. In the reference
  55. * implementation this will not be available.
  56. *
  57. * @return the reflection object, or null if the method can't be found
  58. */
  59. private static Method getDumpHprofDataMethod() {
  60. ClassLoader myLoader = Main.class.getClassLoader();
  61. Class vmdClass;
  62. try {
  63. vmdClass = myLoader.loadClass("dalvik.system.VMDebug");
  64. } catch (ClassNotFoundException cnfe) {
  65. return null;
  66. }
  67. Method meth;
  68. try {
  69. meth = vmdClass.getMethod("dumpHprofData",
  70. new Class[] { String.class });
  71. } catch (NoSuchMethodException nsme) {
  72. System.err.println("Found VMDebug but not dumpHprofData method");
  73. return null;
  74. }
  75. return meth;
  76. }
  77. private static String getDumpFileName() {
  78. File tmpDir = new File("/tmp");
  79. if (tmpDir.exists() && tmpDir.isDirectory()) {
  80. return "/tmp/" + OUTPUT_FILE;
  81. }
  82. File sdcard = new File("/sdcard");
  83. if (sdcard.exists() && sdcard.isDirectory()) {
  84. return "/sdcard/" + OUTPUT_FILE;
  85. }
  86. return null;
  87. }
  88. /**
  89. * Run the various tests for a set period.
  90. */
  91. public static void runTests() {
  92. Robin robin = new Robin();
  93. Deep deep = new Deep();
  94. Large large = new Large();
  95. /* start all threads */
  96. robin.start();
  97. deep.start();
  98. large.start();
  99. /* let everybody run for 10 seconds */
  100. sleep(TEST_TIME * 1000);
  101. quit = true;
  102. try {
  103. /* wait for all threads to stop */
  104. robin.join();
  105. deep.join();
  106. large.join();
  107. } catch (InterruptedException ie) {
  108. System.err.println("join was interrupted");
  109. }
  110. }
  111. /**
  112. * Sleeps for the "ms" milliseconds.
  113. */
  114. public static void sleep(int ms) {
  115. try {
  116. Thread.sleep(ms);
  117. } catch (InterruptedException ie) {
  118. System.err.println("sleep was interrupted");
  119. }
  120. }
  121. /**
  122. * Sleeps briefly, allowing other threads some CPU time to get started.
  123. */
  124. public static void startupDelay() {
  125. sleep(500);
  126. }
  127. }
  128. /**
  129. * Allocates useless objects and holds on to several of them.
  130. *
  131. * Uses a single large array of references, replaced repeatedly in round-robin
  132. * order.
  133. */
  134. class Robin extends Thread {
  135. private static final int ARRAY_SIZE = 40960;
  136. int sleepCount = 0;
  137. public void run() {
  138. Main.startupDelay();
  139. String strings[] = new String[ARRAY_SIZE];
  140. int idx = 0;
  141. while (!Main.quit) {
  142. strings[idx] = makeString(idx);
  143. if (idx % (ARRAY_SIZE / 4) == 0) {
  144. Main.sleep(400);
  145. sleepCount++;
  146. }
  147. idx = (idx + 1) % ARRAY_SIZE;
  148. }
  149. if (Main.DEBUG)
  150. System.out.println("Robin: sleepCount=" + sleepCount);
  151. }
  152. private String makeString(int val) {
  153. try {
  154. return new String("Robin" + val);
  155. } catch (OutOfMemoryError e) {
  156. return null;
  157. }
  158. }
  159. }
  160. /**
  161. * Allocates useless objects in recursive calls.
  162. */
  163. class Deep extends Thread {
  164. private static final int MAX_DEPTH = 61;
  165. private static String strong[] = new String[MAX_DEPTH];
  166. private static WeakReference weak[] = new WeakReference[MAX_DEPTH];
  167. public void run() {
  168. int iter = 0;
  169. boolean once = false;
  170. Main.startupDelay();
  171. while (!Main.quit) {
  172. dive(0, iter);
  173. once = true;
  174. iter += MAX_DEPTH;
  175. }
  176. if (!once) {
  177. System.err.println("not even once?");
  178. return;
  179. }
  180. checkStringReferences();
  181. /*
  182. * Wipe "strong", do a GC, see if "weak" got collected.
  183. */
  184. for (int i = 0; i < MAX_DEPTH; i++)
  185. strong[i] = null;
  186. Runtime.getRuntime().gc();
  187. for (int i = 0; i < MAX_DEPTH; i++) {
  188. if (weak[i].get() != null) {
  189. System.err.println("Deep: weak still has " + i);
  190. }
  191. }
  192. if (Main.DEBUG)
  193. System.out.println("Deep: iters=" + iter / MAX_DEPTH);
  194. }
  195. /**
  196. * Check the results of the last trip through. Everything in
  197. * "weak" should be matched in "strong", and the two should be
  198. * equivalent (object-wise, not just string-equality-wise).
  199. *
  200. * We do that check in a separate method to avoid retaining these
  201. * String references in local DEX registers. In interpreter mode,
  202. * they would retain these references until the end of the method
  203. * or until they are updated to another value.
  204. */
  205. private static void checkStringReferences() {
  206. for (int i = 0; i < MAX_DEPTH; i++) {
  207. if (strong[i] != weak[i].get()) {
  208. System.err.println("Deep: " + i + " strong=" + strong[i] +
  209. ", weak=" + weak[i].get());
  210. }
  211. }
  212. }
  213. /**
  214. * Recursively dive down, setting one or more local variables.
  215. *
  216. * We pad the stack out with locals, attempting to create a mix of
  217. * valid and invalid references on the stack.
  218. */
  219. private String dive(int depth, int iteration) {
  220. try {
  221. String str0;
  222. String str1;
  223. String str2;
  224. String str3;
  225. String str4;
  226. String str5;
  227. String str6;
  228. String str7;
  229. String funStr = "";
  230. switch (iteration % 8) {
  231. case 0:
  232. funStr = str0 = makeString(iteration);
  233. break;
  234. case 1:
  235. funStr = str1 = makeString(iteration);
  236. break;
  237. case 2:
  238. funStr = str2 = makeString(iteration);
  239. break;
  240. case 3:
  241. funStr = str3 = makeString(iteration);
  242. break;
  243. case 4:
  244. funStr = str4 = makeString(iteration);
  245. break;
  246. case 5:
  247. funStr = str5 = makeString(iteration);
  248. break;
  249. case 6:
  250. funStr = str6 = makeString(iteration);
  251. break;
  252. case 7:
  253. funStr = str7 = makeString(iteration);
  254. break;
  255. }
  256. weak[depth] = new WeakReference(funStr);
  257. strong[depth] = funStr;
  258. if (depth+1 < MAX_DEPTH)
  259. dive(depth+1, iteration+1);
  260. else
  261. Main.sleep(100);
  262. return funStr;
  263. } catch (OutOfMemoryError e) {
  264. // Silently ignore OOME since gc stress mode causes them to occur but shouldn't be a
  265. // test failure.
  266. }
  267. return "";
  268. }
  269. private String makeString(int val) {
  270. try {
  271. return new String("Deep" + val);
  272. } catch (OutOfMemoryError e) {
  273. return null;
  274. }
  275. }
  276. }
  277. /**
  278. * Allocates large useless objects.
  279. */
  280. class Large extends Thread {
  281. public void run() {
  282. byte[] chunk;
  283. int count = 0;
  284. int sleepCount = 0;
  285. Main.startupDelay();
  286. while (!Main.quit) {
  287. try {
  288. chunk = new byte[100000];
  289. pretendToUse(chunk);
  290. count++;
  291. if ((count % 500) == 0) {
  292. Main.sleep(400);
  293. sleepCount++;
  294. }
  295. } catch (OutOfMemoryError e) {
  296. }
  297. }
  298. if (Main.DEBUG)
  299. System.out.println("Large: sleepCount=" + sleepCount);
  300. }
  301. public void pretendToUse(byte[] chunk) {}
  302. }