Why is ScrollView / LazyVStack retaining Views which causes memory leaks in the end?

Recently I noticed how my ViewModels aren't deallocating and they end up as a memory leaks. I found something similar in this thread but this is also happening without using @Observation. Check the source code below:

class CellViewModel: Identifiable {
    
    let id = UUID()
    var color: Color = Color.red
    
    init() { print("init") }
    deinit { print("deinit") }
}

struct CellView: View {
    
    let viewModel: CellViewModel
    
    var body: some View {
        ZStack {
            Color(viewModel.color)
            Text(viewModel.id.uuidString)
        }
    }
}

@main
struct LeakApp: App {
    
    @State var list = [CellViewModel]()
    
    var body: some Scene {
        
        WindowGroup {
        
            Button("Add") {
                list.append(CellViewModel())
            }
            
            Button("Remove") {
                list = list.dropLast()
            }
            
            ScrollView {
                LazyVStack {
                    ForEach(list) { model in
                        CellView(viewModel: model)
                    }
                }
            }
        }
    }
}

When I tap the Add button twice in the console I will see "init" message twice. So far so good. But then I click the Remove button twice and I don't see any "deinit" messages.

I used the Debug Memory Graph in Xcode and it showed me that two CellViewModel objects are in the memory and they are owned by the CellView and some other objects that I don't know where are they coming from (I assume from SwiftUI internally).

I tried using VStack instead of LazyVStack and that did worked a bit better but still not 100% "deinits" were in the Console.

I tried using weak var

struct CellView: View {    
    weak var viewModel: CellViewModel?
    ....
}

but this also helped only partially.

The only way to fully fix this is to have a separate class that holds the list of items and to use weak var viewModel: CellViewModel?. Something like this:

class CellViewModel: Identifiable {
    
    let id = UUID()
    var color: Color = Color.red
    
    init() { print("init") }
    deinit { print("deinit") }
}

struct CellView: View {
    
    var viewModel: CellViewModel?
    
    var body: some View {
        ZStack {
            if let viewModel = viewModel {
                Color(viewModel.color)
                Text(viewModel.id.uuidString)
            }
        }
    }
}

@Observable
class ListViewModel {
    
    var list = [CellViewModel]()
    
    func insert() {
        list.append(CellViewModel())
    }
    
    func drop() {
        list = list.dropLast()
    }
}

@main
struct LeakApp: App {
    
    @State var viewModel = ListViewModel()
    
    var body: some Scene {
        
        WindowGroup {
        
            Button("Add") {
                viewModel.insert()
            }
            
            Button("Remove") {
                viewModel.drop()
            }
            
            ScrollView {
                LazyVStack {
                    ForEach(viewModel.list) { model in
                        CellView(viewModel: model)
                    }
                }
            }
        }
    }
}

But this won't work if I want to use @Bindable such as

@Bindable var viewModel: CellViewModel?

I don't understand why SwiftUI doesn't want to release the objects?

Why is ScrollView / LazyVStack retaining Views which causes memory leaks in the end?
 
 
Q