• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<lambda>null1 package shark
2 
3 import java.io.File
4 import kotlin.reflect.KClass
5 import org.assertj.core.api.Assertions.assertThat
6 import org.junit.Rule
7 import org.junit.Test
8 import org.junit.rules.TemporaryFolder
9 import shark.HprofHeapGraph.Companion.openHeapGraph
10 import shark.HprofRecord.HeapDumpRecord.ObjectRecord.PrimitiveArrayDumpRecord.IntArrayDump
11 import shark.PrimitiveType.INT
12 
13 class JvmHprofParsingTest {
14 
15   @get:Rule
16   var testFolder = TemporaryFolder()
17 
18   @Test fun dumpHeapAndReadString() {
19     val hprofFolder = testFolder.newFolder()
20     val hprofFile = File(hprofFolder, "jvm_heap.hprof")
21 
22     JvmTestHeapDumper.dumpHeap(hprofFile.absolutePath)
23 
24     hprofFile.openHeapGraph().use { graph ->
25       val testInstances = graph.instances
26         .filter { it.instanceClassName == JvmHprofParsingTest::class.name }
27         .toList()
28 
29       assertThat(testInstances).hasSize(1)
30       val test = testInstances[0]
31       val folderPath = test[JvmHprofParsingTest::class.name, "testFolder"]!!
32         .valueAsInstance!![TemporaryFolder::class.name, "folder"]!!
33         .valueAsInstance!![File::class.name, "path"]!!
34         .value.readAsJavaString()!!
35 
36       assertThat(folderPath).isEqualTo(testFolder.root.path)
37     }
38   }
39 
40   @Test fun `JVM object array class name is translated to brackets`() {
41     val objectArray = arrayOf<JvmHprofParsingTest>()
42     val hprofFile = dumpHeapRetaining(objectArray)
43 
44     val expectedArrayClassName = "${JvmHprofParsingTest::class.java.name}[]"
45 
46     hprofFile.openHeapGraph().use { graph ->
47       val arrayClass = graph.findClassByName(expectedArrayClassName)
48       assertThat(arrayClass).isNotNull
49       assertThat(arrayClass!!.isObjectArrayClass).isTrue()
50       assertThat(arrayClass.name).isEqualTo(expectedArrayClassName)
51 
52       val array = arrayClass.objectArrayInstances.single()
53       assertThat(array.arrayClassName).isEqualTo(expectedArrayClassName)
54     }
55   }
56 
57   @Test fun `JVM multi dimension object array class name is translated to brackets`() {
58     val objectArray = arrayOf(arrayOf(), arrayOf<JvmHprofParsingTest>())
59     val hprofFile = dumpHeapRetaining(objectArray)
60 
61     val expectedArrayClassName = "${JvmHprofParsingTest::class.java.name}[][]"
62 
63     hprofFile.openHeapGraph().use { graph ->
64       val arrayClass = graph.findClassByName(expectedArrayClassName)
65       assertThat(arrayClass).isNotNull
66       assertThat(arrayClass!!.isObjectArrayClass).isTrue()
67       assertThat(arrayClass.name).isEqualTo(expectedArrayClassName)
68 
69       val array = arrayClass.objectArrayInstances.single()
70       assertThat(array.arrayClassName).isEqualTo(expectedArrayClassName)
71     }
72   }
73 
74   @Test fun `JVM primitive wrapper array class name is translated to brackets`() {
75     val hprofFile = dumpHeapRetaining(arrayOfNulls<Int?>(42))
76 
77     val expectedArrayClassName = "java.lang.Integer[]"
78 
79     hprofFile.openHeapGraph().use { graph ->
80       val arrayClass = graph.findClassByName(expectedArrayClassName)
81       assertThat(arrayClass).isNotNull
82       assertThat(arrayClass!!.isObjectArrayClass).isTrue()
83       assertThat(arrayClass.name).isEqualTo(expectedArrayClassName)
84 
85       val array = arrayClass.objectArrayInstances.single { it.readElements().count() == 42 }
86       assertThat(array.arrayClassName).isEqualTo(expectedArrayClassName)
87     }
88   }
89 
90   @Test fun `JVM multi dimension wrapper primitive array class name is translated to brackets`() {
91     val hprofFile = dumpHeapRetaining(arrayOf(arrayOf(), arrayOf<Int?>()))
92 
93     val expectedArrayClassName = "java.lang.Integer[][]"
94 
95     hprofFile.openHeapGraph().use { graph ->
96       val arrayClass = graph.findClassByName(expectedArrayClassName)
97       assertThat(arrayClass).isNotNull
98       assertThat(arrayClass!!.isObjectArrayClass).isTrue()
99       assertThat(arrayClass.name).isEqualTo(expectedArrayClassName)
100 
101       val array = arrayClass.objectArrayInstances.single { it.readElements().count() == 2 }
102       assertThat(array.arrayClassName).isEqualTo(expectedArrayClassName)
103     }
104   }
105 
106   @Test fun `JVM primitive array class name is translated to brackets`() {
107     val hprofFile = dumpHeapRetaining(IntArray(42).apply { this[0] = 0xDad })
108 
109     val expectedArrayClassName = "int[]"
110 
111     hprofFile.openHeapGraph().use { graph ->
112       val arrayClass = graph.findClassByName(expectedArrayClassName)
113       assertThat(arrayClass).isNotNull
114       assertThat(arrayClass!!.isPrimitiveArrayClass).isTrue()
115       assertThat(arrayClass.name).isEqualTo(expectedArrayClassName)
116 
117       val array = arrayClass.primitiveArrayInstances.single {
118         it.primitiveType == INT && it.readRecord()
119           .run { size == 42 && (this as IntArrayDump).array[0] == 0xDad }
120       }
121       assertThat(array.arrayClassName).isEqualTo(expectedArrayClassName)
122     }
123   }
124 
125   @Test fun `JVM multi dimension primitive array class name is translated to brackets`() {
126     val hprofFile = dumpHeapRetaining(arrayOf(IntArray(42), IntArray(42)))
127 
128     val expectedArrayClassName = "int[][]"
129 
130     hprofFile.openHeapGraph().use { graph ->
131       val arrayClass = graph.findClassByName(expectedArrayClassName)
132       assertThat(arrayClass).isNotNull
133       assertThat(arrayClass!!.isPrimitiveArrayClass).isFalse()
134       assertThat(arrayClass.name).isEqualTo(expectedArrayClassName)
135 
136       val array = arrayClass.objectArrayInstances.single {
137         it.readRecord().elementIds.size == 2
138       }
139       assertThat(array.arrayClassName).isEqualTo(expectedArrayClassName)
140     }
141   }
142 
143   private fun dumpHeapRetaining(retained: Any): File {
144     val hprofFolder = testFolder.newFolder()
145     val hprofFile = File(hprofFolder, "jvm_heap.hprof")
146     JvmTestHeapDumper.dumpHeap(hprofFile.absolutePath)
147     // Dumb check to prevent instance from being garbage collected.
148     check(retained::class::class.isInstance(KClass::class))
149     return hprofFile
150   }
151 }
152 
153 private val KClass<out Any>.name: String
154   get() = this.java.name
155