【Kotlin/Android】WeakReferenceの使い方!弱参照とメモリの確保/解放

【Kotlin/Android】WeakReferenceの使い方!弱参照とメモリの確保/解放

この記事からわかること

  • Android Studio/KotlinWeakReference(弱参照)とは?
  • 強参照との違い
  • メモリ確保解放

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

WeakReferenceとは?

KotlinのWeakReferenceオブジェクトへの参照を弱参照にするためのクラスです。通常オブジェクトは強参照でメモリアドレスと関連づいています。これを明示的に弱参照にすることでガーベジコレクションによるメモリの解放対象となり、メモリリークの発生を抑制することが可能になっています。

WeakReferenceの使い方の前にメモリの確保と解放の流れを理解しておきます。

メモリの確保

メモリが確保されるのはクラスのインスタンスを生成した時などです。そこからプロパティや変数に格納されるとそのメモリ(インスタンス)の参照という形で紐付けがカウントされます。この参照を強参照と呼びます。

data class Person (
    var name: String
)
// 強参照でメモリと紐付け
var person1: Person? = Person("ame")

メモリの解放

メモリが解放されるのはオブジェクトへの参照がなくなった時です。具体的には変数にnullを格納して参照を解放した場合や、メソッドのスコープから外れてそのオブジェクトへの参照がなくなった場合などです。

// 変数にnullを格納
person1 = null
// personはこのメソッドのスコープ内でのみ有効のローカル変数
fun someFunction() {
    val person = Person("ame")
} // someFunctionを抜けるとpersonへの参照がなくなる

メモリが解放されない

逆に言うとオブジェクトへの参照がなくならないとメモリは解放されませんPersonオブジェクトをコピーして変数に格納するとメモリの参照カウントは2になります。この状態でperson1nullを格納してもperson2からオブジェクトに参照できるのでメモリは解放されず、person2の参照がなくなった場合にメモリが解放されます。

var person1: Person? = Person("ame")
var person2 = person1

println("Before BC: ${person1?.name}") // Before BC: ame
println("Before BC: ${person2?.name}") // Before BC: ame

// 強参照をnullにする
person1 = null

println("Before BC: ${person1?.name}") // Before BC: null
println("Before BC: ${person2?.name}") // Before BC: ame

// ガベージコレクションを実行
System.gc()

println("After GC: ${person1?.name}") // After BC: null
println("After BC: ${person2?.name}") // After BC: ame

// 強参照をnullにする(ここでメモリが解放される)
person2 = null

ガーベジコレクションを明示的に実行してもメモリは解放されません。メモリ消費量の確認やSystem.gc()などについては以下の記事を参考にしてください。

WeakReferenceで弱参照にする

先ほどのようにコピーをたくさん作成するとその数だけ片付けをしないとメモリが解放されず、メモリリークを引き起こす原因になります。これを解消できるのがWeakReferenceです。WeakReferenceのコンストラクタに対象のオブジェクトを渡し、WeakReferenceでラップした状態にします。値を取得する際getメソッドを使用します。

メモリが解放されないで紹介したコードをWeakReferenceに置き換えると結果が異なりガベージコレクションが発生した後にはメモリが解放されていることがわかります。

var person1: Person? = Person("ame")
val person2 = WeakReference(person1)

println("Before BC: ${person1?.name}") // Before BC: ame
println("Before BC: ${person2.get()?.name}") // Before BC: ame

// 強参照をnullにする
person1 = null

println("Before BC: ${person1?.name}") // Before BC: null
println("Before BC: ${person2.get()?.name}") // Before BC: ame

// ガベージコレクションを実行
System.gc()

println("After GC: ${person1?.name}") // After BC: null
println("After GC: ${person2.get()?.name}") // After BC: null

// person2を明示的にnullにしなくてもガベージコレクションの対象になり解放される
// person2 = null

clearメソッド

clearメソッドを実行するとオブジェクトへの参照をクリアすることができます。

 person2.clear()
println("Before BC: ${person2.get()?.name}") // null

メモリリークを検知できるライブラリ

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index