Unverified Commit 5bc7d314 authored by Nikolay Igotti's avatar Nikolay Igotti Committed by GitHub

Create automated background memory manager. (#141)

parent cd99819e
......@@ -13,7 +13,7 @@ plugins {
id("de.undercouch.download") version "4.1.1"
}
val coroutinesVersion = "1.4.1"
val coroutinesVersion = "1.5.0"
buildscript {
dependencies {
......@@ -556,6 +556,7 @@ val createChecksums by project.tasks.registering(org.gradle.crypto.checksum.Chec
}
val skikoJvmRuntimeJar by project.tasks.registering(Jar::class) {
dependsOn(createChecksums)
archiveBaseName.set("skiko-$target")
from(skikoJvmJar.map { zipTree(it.archiveFile) })
from(maybeSign.get().outputs.files)
......
package org.jetbrains.skiko
import kotlinx.coroutines.*
import java.util.concurrent.atomic.AtomicInteger
/**
* This class is intended to mitigate issues coming from the situation that we have
* pretty large native peers (Skia objects) for rather tiny Java wrappers.
* It is especially visible for situation with paragraph classes.
* As a result, memory consumption grows dramatically.
* To solve this issue, we force periodic GC if certain amount of frames was rendered,
* making sure that we'll have memory consumption under control.
*/
internal object FrameWatcher {
var gcDelayMillis = 30_000L
var minFramesToRenderer = 1_000
fun start() {
// We initiate GC on IO threads, so that rendering is not blocked in
// cases of concurrent collectors.
@OptIn(DelicateCoroutinesApi::class)
GlobalScope.launch(Dispatchers.IO) {
while (true) {
// Wait some time between collection attempts.
delay(gcDelayMillis)
// Ensure that certain number of frames were rendered, as we allocate Skia
// garbage when rendering.
if (frameCounter.get() > minFramesToRenderer) {
System.gc()
frameCounter.set(0)
}
}
}
}
fun nextFrame() {
frameCounter.addAndGet(1)
}
private val frameCounter = AtomicInteger(0)
}
......@@ -2,12 +2,13 @@ package org.jetbrains.skiko
import javax.swing.UIManager
object Setup {
internal object Setup {
fun init(
noEraseBackground: Boolean = System.getProperty("skiko.rendering.noerasebackground") != "false",
globalLAF: Boolean = System.getProperty("skiko.rendering.laf.global") == "true",
useScreenMenuBar: Boolean = System.getProperty("skiko.rendering.useScreenMenuBar") != "false",
autoLinuxDpi: Boolean = System.getProperty("skiko.linux.autodpi") == "true"
autoLinuxDpi: Boolean = System.getProperty("skiko.linux.autodpi") == "true",
automateGC: Boolean = System.getProperty("skiko.gc.auto") != "false"
) {
if (hostOs == OS.Linux && autoLinuxDpi) {
val scale = linuxGetSystemDpiScale()
......@@ -29,6 +30,10 @@ object Setup {
} catch (e: UnsupportedOperationException) {
// Not all platforms allow this.
}
if (automateGC) {
FrameWatcher.start()
}
}
}
......
......@@ -350,6 +350,7 @@ open class SkiaLayer(
}
flush()
}
FrameWatcher.nextFrame()
}
// Captures current layer as bitmap.
......
......@@ -101,7 +101,9 @@ class SeveralClassloaders {
val jar = System.getProperty("skiko.jar.path")
val stdlibClass = Class.forName("kotlin.jvm.internal.Intrinsics")
val stdLibJar = stdlibClass.protectionDomain.codeSource.location
val urls = listOf(Paths.get(jar).toUri().toURL(), stdLibJar)
val coroutinesClass = Class.forName("kotlinx.coroutines.CoroutineDispatcher")
val coroutinesJar = coroutinesClass.protectionDomain.codeSource.location
val urls = listOf(Paths.get(jar).toUri().toURL(), stdLibJar, coroutinesJar)
val loaders = mutableListOf<ClassLoader>()
repeat(4) {
loaders += PlatformAndURLClassLoader(urls)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment