[LL FIR] fix memory leak from LLFirSessionProvider for the module

LLFirSessionProvider stores all transitive module dependencies,
even if they are not needed or already invalidated and garbage collected

Now, the dependencies are stored on the weak references, and so then nobody uses them, they will be garbage collected
This commit is contained in:
Ilya Kirillov
2022-12-12 19:00:03 +01:00
committed by Space Team
parent 34e4645385
commit 9cf77e19be
2 changed files with 42 additions and 9 deletions
@@ -6,20 +6,20 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions
import com.intellij.openapi.project.Project
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.analysis.api.impl.barebone.annotations.Immutable
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirModuleData
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirDependentModuleProviders
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.FirSessionProvider
import org.jetbrains.kotlin.fir.resolve.providers.dependenciesSymbolProvider
import java.lang.ref.WeakReference
@Immutable
class LLFirSessionProvider internal constructor(
val project: Project,
internal val rootModuleSession: LLFirResolvableModuleSession,
private val ktModuleToSession: Map<KtModule, LLFirSession>
private val ktModuleToSession: KtModuleToSessionMapping
) : FirSessionProvider() {
override fun getSession(moduleData: FirModuleData): LLFirSession {
requireIsInstance<LLFirModuleData>(moduleData)
@@ -27,11 +27,44 @@ class LLFirSessionProvider internal constructor(
}
fun getSession(module: KtModule): LLFirSession =
ktModuleToSession.getValue(module)
ktModuleToSession.getSession(module)
fun getResolvableSession(module: KtModule): LLFirResolvableModuleSession =
ktModuleToSession.getValue(module) as LLFirResolvableModuleSession
ktModuleToSession.getSession(module) as LLFirResolvableModuleSession
@get:TestOnly
val allSessions: Collection<LLFirSession>
get() = ktModuleToSession.values
get() = ktModuleToSession.getAllSessions()
}
internal abstract class KtModuleToSessionMapping {
abstract fun getSession(module: KtModule): LLFirSession
@TestOnly
abstract fun getAllSessions(): Collection<LLFirSession>
}
internal class KtModuleToSessionMappingByMapImpl(
private val map: Map<KtModule, LLFirSession>
) : KtModuleToSessionMapping() {
override fun getSession(module: KtModule): LLFirSession =
map.getValue(module)
override fun getAllSessions(): Collection<LLFirSession> =
map.values
}
internal class KtModuleToSessionMappingByWeakValueMapImpl(
initialMap: Map<KtModule, LLFirSession>
) : KtModuleToSessionMapping() {
private val softValuesMap = initialMap.entries.associate { (key, value) -> key to WeakReference(value) }
override fun getSession(module: KtModule): LLFirSession {
val softReference = softValuesMap.getValue(module)
return softReference.get()
?: error("soft reference for $module was invalidated")
}
override fun getAllSessions(): Collection<LLFirSession> =
softValuesMap.keys.map { getSession(it) }
}
@@ -48,7 +48,7 @@ class LLFirSessionProviderStorage(val project: Project) {
is KtNotUnderContentRootModule -> {
val session = LLFirNonUnderContentRootSessionFactory.getInstance(project)
.getNonUnderContentRootSession(useSiteKtModule)
LLFirSessionProvider(project, session, mapOf(useSiteKtModule to session))
LLFirSessionProvider(project, session, KtModuleToSessionMappingByMapImpl(mapOf(useSiteKtModule to session)))
}
else -> error("Unexpected ${useSiteKtModule::class.simpleName}")
@@ -72,7 +72,7 @@ class LLFirSessionProviderStorage(val project: Project) {
)
sessions to session
}
return LLFirSessionProvider(project, session, sessions)
return LLFirSessionProvider(project, session, KtModuleToSessionMappingByWeakValueMapImpl(sessions))
}
@@ -93,7 +93,7 @@ class LLFirSessionProviderStorage(val project: Project) {
)
sessions to session
}
return LLFirSessionProvider(project, session, sessions)
return LLFirSessionProvider(project, session, KtModuleToSessionMappingByWeakValueMapImpl(sessions))
}
}