Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

NestedAroundClosureMemoryLeakTest.java 3.2KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import java.lang.reflect.Field;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.Set;
  5. import java.util.concurrent.ExecutorService;
  6. import java.util.concurrent.Executors;
  7. public class NestedAroundClosureMemoryLeakTest {
  8. private static final int NUM_THREAD_POOLS = 4;
  9. private static final int THREAD_POOL_SIZE = 3;
  10. public static void main(String[] args) throws Exception {
  11. testNoMemoryLeak_ThreadLocalCleared();
  12. }
  13. /**
  14. * Tests that the thread-locals of the spawned threads are either null or contain all null elements
  15. */
  16. public static void testNoMemoryLeak_ThreadLocalCleared() throws Exception {
  17. List<ExecutorService> executorServices = createExecutorServicesWithFixedThreadPools();
  18. try {
  19. executeTasks(executorServices);
  20. Field mapField = Thread.class.getDeclaredField("threadLocals");
  21. mapField.setAccessible(true);
  22. Set<Thread> threads = Thread.getAllStackTraces().keySet();
  23. System.out.println("Number of pool threads = " + threads.stream().filter(thread -> thread.getName().contains("pool")).count());
  24. threads.stream()
  25. .filter(thread -> thread.getName().contains("pool"))
  26. .forEach(thread -> {
  27. try {
  28. Object threadLocals = mapField.get(thread);
  29. if (threadLocals != null) {
  30. Field tableField = threadLocals.getClass().getDeclaredField("table");
  31. tableField.setAccessible(true);
  32. Object[] threadLocalTable = (Object[]) tableField.get(threadLocals);
  33. if (threadLocalTable != null) {
  34. for (Object entry : threadLocalTable) {
  35. if (entry == null)
  36. continue;
  37. Field entryValueField = entry.getClass().getDeclaredField("value");
  38. entryValueField.setAccessible(true);
  39. throw new RuntimeException(
  40. "All thread-locals should be null, but found entry with value " + entryValueField.get(entry)
  41. );
  42. }
  43. }
  44. }
  45. }
  46. catch (RuntimeException rte) {
  47. throw rte;
  48. }
  49. catch (Exception e) {
  50. throw new RuntimeException(e);
  51. }
  52. });
  53. System.out.println("Test passed - all thread-locals are null");
  54. }
  55. finally {
  56. for (ExecutorService executorService : executorServices)
  57. executorService.shutdown();
  58. }
  59. }
  60. private static List<ExecutorService> createExecutorServicesWithFixedThreadPools() {
  61. List<ExecutorService> executorServiceList = new ArrayList<>(NestedAroundClosureMemoryLeakTest.NUM_THREAD_POOLS);
  62. for (int i = 0; i < NestedAroundClosureMemoryLeakTest.NUM_THREAD_POOLS; i++)
  63. executorServiceList.add(Executors.newFixedThreadPool(THREAD_POOL_SIZE));
  64. return executorServiceList;
  65. }
  66. private static void executeTasks(List<ExecutorService> executorServices) throws Exception {
  67. for (ExecutorService executorService : executorServices) {
  68. for (int i = 0; i < THREAD_POOL_SIZE * 2; i++)
  69. new Task(executorService).doSomething();
  70. }
  71. System.out.println("Finished executing tasks");
  72. // Sleep to take a memory dump
  73. // Thread.sleep(500000);
  74. }
  75. }