Skip to content

Commit 7db2e00

Browse files
authored
Fix memory leak (#36)
Fixes #35
1 parent 8e2df49 commit 7db2e00

File tree

4 files changed

+55
-7
lines changed

4 files changed

+55
-7
lines changed

library/src/commonMain/kotlin/kotlinx/serialization/csv/decode/CsvReader.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,15 +190,15 @@ internal class CsvReader(
190190
*/
191191
fun unmark() {
192192
source.unmark()
193-
marks.removeAt(marks.size - 1)
193+
marks.removeLast()
194194
}
195195

196196
/**
197197
* Reset the stream to the last [mark]ed position (and remove the mark).
198198
*/
199199
fun reset() {
200200
source.reset()
201-
recordNo = marks.removeAt(marks.size - 1)
201+
recordNo = marks.removeLast()
202202
}
203203

204204
/**

library/src/commonMain/kotlin/kotlinx/serialization/csv/source/CharStreamSource.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,13 @@ internal class CharStreamSource(
7272
}
7373

7474
override fun unmark() {
75-
marks.removeAt(marks.lastIndex)
75+
marks.removeLast()
76+
77+
if (marks.isEmpty()) queue.clear()
7678
}
7779

7880
override fun reset() {
79-
offset = marks[marks.lastIndex]
80-
marks.removeAt(marks.lastIndex)
81+
offset = marks.last()
82+
marks.removeLast()
8183
}
8284
}

library/src/commonMain/kotlin/kotlinx/serialization/csv/source/StringSource.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ internal class StringSource(
3535
}
3636

3737
override fun unmark() {
38-
marks.removeAt(marks.size - 1)
38+
marks.removeLast()
3939
}
4040

4141
override fun reset() {
42-
position = marks.removeAt(marks.size - 1)
42+
position = marks.removeLast()
4343
}
4444

4545
override fun toString(): String =

library/src/jvmTest/kotlin/kotlinx/serialization/csv/example/SteamingTest.kt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import kotlinx.coroutines.async
55
import kotlinx.coroutines.delay
66
import kotlinx.coroutines.test.runTest
77
import kotlinx.serialization.ExperimentalSerializationApi
8+
import kotlinx.serialization.Serializable
89
import kotlinx.serialization.csv.Csv
910
import kotlinx.serialization.csv.example.Tire.Axis.FRONT
1011
import kotlinx.serialization.csv.example.Tire.Axis.REAR
@@ -13,13 +14,17 @@ import kotlinx.serialization.csv.example.Tire.Side.RIGHT
1314
import kotlinx.serialization.csv.recordReader
1415
import kotlinx.serialization.csv.recordWriter
1516
import kotlinx.serialization.modules.SerializersModule
17+
import java.io.File
18+
import java.io.FileInputStream
19+
import java.io.FileOutputStream
1620
import java.io.PipedReader
1721
import java.io.PipedWriter
1822
import kotlin.io.buffered
1923
import kotlin.io.println
2024
import kotlin.test.Test
2125
import kotlin.test.assertEquals
2226
import kotlin.time.Duration.Companion.milliseconds
27+
import kotlin.time.Duration.Companion.minutes
2328
import kotlin.use
2429
import kotlin.uuid.Uuid
2530

@@ -129,4 +134,45 @@ class SteamingTest {
129134

130135
assertEquals(testData, result)
131136
}
137+
138+
@Test
139+
fun testLargeFile() = runTest(timeout = 10.minutes) {
140+
@Serializable
141+
data class Entry(
142+
val id: Int,
143+
val value: String,
144+
)
145+
146+
val csv = Csv {
147+
hasHeaderRecord = true
148+
}
149+
150+
val file = File("file.csv")
151+
152+
println("Writing...")
153+
FileOutputStream(file).buffered().use { output ->
154+
val writer = csv.recordWriter(Entry.serializer(), output)
155+
repeat(10_000_000) {
156+
val entry = Entry(it, "Value $it")
157+
writer.write(entry)
158+
159+
if (entry.id % 100_000 == 0) {
160+
println("$entry written.")
161+
}
162+
}
163+
}
164+
165+
println("Reading...")
166+
FileInputStream(file).buffered().use { input ->
167+
val reader = csv.recordReader(Entry.serializer(), input)
168+
169+
reader.asSequence().forEach { entry ->
170+
if (entry.id % 100_000 == 0) {
171+
println("$entry read.")
172+
}
173+
}
174+
}
175+
176+
file.delete()
177+
}
132178
}

0 commit comments

Comments
 (0)