Skip to content

Commit 176b417

Browse files
committed
Start working on reducing the memory consumption
1 parent 1770738 commit 176b417

File tree

2 files changed

+34
-15
lines changed

2 files changed

+34
-15
lines changed

Diff for: kotlinx-coroutines-core/common/src/internal/LockFreeLinkedList.common.kt

+11-15
Original file line numberDiff line numberDiff line change
@@ -46,20 +46,18 @@ internal open class LockFreeLinkedListNode {
4646
}
4747

4848
/** @suppress **This is unstable API and it is subject to change.** */
49-
internal open class LockFreeLinkedListHead {
50-
private val head = LockFreeLinkedListSegment(
51-
id = 0,
52-
prev = null,
53-
pointers = 2,
54-
head = this,
55-
)
56-
private val tail = atomic(head)
49+
internal open class LockFreeLinkedListHead: LockFreeLinkedListSegment(
50+
id = 0,
51+
prev = null,
52+
pointers = 2,
53+
) {
54+
private val tail = atomic<LockFreeLinkedListSegment>(this)
5755
private val nextElement = atomic(0L)
5856

5957
/**
6058
* The list of bits that are forbidden from entering the list.
6159
*
62-
* TODO: we can store this in the extra bits in [head], there's enough space for that there, and it's never removed.
60+
* TODO: we can store this in `cleanedAndPointers`, there's enough space for that there.
6361
*/
6462
private val forbiddenBits: AtomicInt = atomic(0)
6563

@@ -122,17 +120,14 @@ internal open class LockFreeLinkedListHead {
122120
null
123121
}
124122
}
123+
124+
override val head: LockFreeLinkedListHead get() = this
125125
}
126126

127127
internal open class LockFreeLinkedListSegment(
128128
id: Long,
129129
prev: LockFreeLinkedListSegment?,
130130
pointers: Int,
131-
/** Used only during promoting of a single node to a list to ensure wait-freedom of the promotion operation.
132-
* Without this, promotion can't be implemented without a (possibly bounded) spin loop: once the node is committed
133-
* to be part of some list, the other threads can't do anything until that one thread sets the state to be the
134-
* head of the list. */
135-
@JvmField val head: LockFreeLinkedListHead,
136131
) : Segment<LockFreeLinkedListSegment>(id = id, prev = prev, pointers = pointers)
137132
{
138133
/** Each cell is a [LockFreeLinkedListNode], a [BrokenForSomeElements], or `null`. */
@@ -188,6 +183,8 @@ internal open class LockFreeLinkedListSegment(
188183
override fun onCancellation(index: Int, cause: Throwable?, context: CoroutineContext) {
189184
throw UnsupportedOperationException("Cancellation is not supported on LockFreeLinkedList")
190185
}
186+
187+
open val head: LockFreeLinkedListHead get() = prev!!.head
191188
}
192189

193190
internal class Address(@JvmField val segment: LockFreeLinkedListSegment, @JvmField val index: Int)
@@ -197,7 +194,6 @@ private fun createSegment(id: Long, prev: LockFreeLinkedListSegment): LockFreeLi
197194
id = id,
198195
prev = prev,
199196
pointers = 0,
200-
head = prev.head
201197
)
202198

203199
private const val SEGMENT_SIZE = 8

Diff for: kotlinx-coroutines-core/jvm/test/MemoryFootprintTest.kt

+23
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package kotlinx.coroutines
33
import kotlinx.coroutines.testing.*
44
import org.junit.Test
55
import org.openjdk.jol.info.ClassLayout
6+
import org.openjdk.jol.info.GraphLayout
67
import kotlin.test.*
78

89

@@ -14,9 +15,31 @@ class MemoryFootprintTest : TestBase(true) {
1415
@Test
1516
fun testCancellableContinuationFootprint() = assertLayout(CancellableContinuationImpl::class.java, 48)
1617

18+
19+
@Test
20+
fun testJobSize() {
21+
assertTotalSize(jobWithChildren(1), 112)
22+
assertTotalSize(jobWithChildren(2), 336) // originally: 192
23+
assertTotalSize(jobWithChildren(3), 416) // originally: 56
24+
assertTotalSize(jobWithChildren(4), 496) // originally: 304
25+
}
26+
27+
private fun jobWithChildren(numberOfChildren: Int): Job {
28+
val result = Job()
29+
repeat(numberOfChildren) {
30+
Job(result)
31+
}
32+
return result
33+
}
34+
1735
private fun assertLayout(clz: Class<*>, expectedSize: Int) {
1836
val size = ClassLayout.parseClass(clz).instanceSize()
1937
// println(ClassLayout.parseClass(clz).toPrintable())
2038
assertEquals(expectedSize.toLong(), size)
2139
}
40+
41+
private fun assertTotalSize(instance: Job, expectedSize: Int) {
42+
val size = GraphLayout.parseInstance(instance).totalSize()
43+
assertEquals(expectedSize.toLong(), size)
44+
}
2245
}

0 commit comments

Comments
 (0)