-
-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Widgets prematurely garbage collected #74
Comments
I just discovered that this is unrelated to the lazy loading of the texture. Completely removing it and using an empty class MyPicture < GObject::Object
include Gdk::Paintable
def initialize
super()
end
@[GObject::Virtual]
def do_snapshot(snapshot : Gdk::Snapshot, width : Float64, height : Float64) : Nil
end
@[GObject::Virtual]
def do_get_intrinsic_width
0
end
@[GObject::Virtual]
def do_get_intrinsic_height
0
end
@[GObject::Virtual]
def do_get_flags
Gdk::PaintableFlags::None
end
@[GObject::Virtual]
def do_get_intrinsic_aspect_ratio
1_f64
end
@[GObject::Virtual]
def do_get_current_image
self
end
end Using a Something about the way I'm using the class must conflict with the GC 🤔 |
Another discovery. Disabling GC but manually calling |
Immix doesn't even implement the additional allocating functions used by this shard, so that doesn't work. https://github.com/hugopl/gi-crystal/blob/main/src/gi-crystal/toggle_ref_manager.cr |
so is it the equivalent of |
I've reduced the example even further require "libadwaita"
{% `blueprint-compiler batch-compile ./src/ui/compiled ./src/ui/ ./src/ui/*.blp` %}
Gio.register_resource("src/ui/window.gresource.xml", "src/ui")
@[Gtk::UiTemplate(resource: "/moe/shisho/compiled/MinimalExample.ui", children: %w(grid_view scroll))]
class MainWindow < Adw::ApplicationWindow
include Gtk::WidgetTemplate
def initialize(application : Adw::Application)
super(application: application)
# Main window widget setup
scroll = Gtk::ScrolledWindow.cast(template_child("scroll"))
grid_view = Gtk::GridView.cast(template_child("grid_view"))
my_list = Gtk::SingleSelection.new
list_store = Gio::ListStore.new(MyItem.g_type)
my_list.model = list_store
grid_view.model = my_list
scroll.child = grid_view
# Assigning a few `MyItem`s to the ListStore.
array = [] of MyItem
10.times do |x|
array << MyItem.new
end
list_store.splice(0, 0, array)
end
end
# In a normal use-case, this would have other properties that hold text for example
# to create a proper `ListView` row or something.
class MyItem < GObject::Object
@[GObject::Property]
property picture : MyPicture # This is a paintable
def initialize
super()
@picture = MyPicture.new
end
end
# Paintable that does literally nothing.
class MyPicture < GObject::Object
include Gdk::Paintable
def initialize
super()
end
@[GObject::Virtual]
def do_snapshot(snapshot : Gdk::Snapshot, width : Float64, height : Float64) : Nil
end
end
# General application stuff
class App < Adw::Application
def initialize
super(application_id: "minimal.example", flags: Gio::ApplicationFlags::DefaultFlags)
end
@[GObject::Virtual]
def activate
window = active_window.nil? ? MainWindow.new(application: self) : active_window.not_nil!
window.present
end
end
app = App.new
exit(app.run) with the blueprint
As you can see, I'm not doing anything fancy. Assigning a few This example crashes after resizing the window a bunch. With Custom Here's a video demonstrating the issue: Screencast.From.2024-12-26.21-14-55.mp4I would LOVE to help, but I know little to no C. If there is anything I can do to assist you please let me know! ❤️ |
Another finding, the issue is entirely caused by the following: class MyItem < GObject::Object
@[GObject::Property]
property picture : MyPicture
def initialize
super()
@picture = MyPicture.new
end
end
# Paintable that does literally nothing.
class MyPicture < GObject::Object
include Gdk::Paintable
def initialize
super()
end
@[GObject::Virtual]
def do_snapshot(snapshot : Gdk::Snapshot, width : Float64, height : Float64) : Nil
end
end Replacing class MyItem < GObject::Object
@[GObject::Property]
property picture : Gtk::Picture.new
def initialize
super()
end
end Further minimising the issue and skipping the
list_store = Gio::ListStore.new(MyPicture.g_type)
array = [] of MyPicture
10.times do |x|
array << MyPicture.new
end
list_store.splice(0, 0, array)
class MyPicture < GObject::Object
include Gdk::Paintable
def initialize
super()
end
@[GObject::Virtual]
def do_snapshot(snapshot : Gdk::Snapshot, width : Float64, height : Float64) : Nil
end
end |
Final comment: class MainWindow < Adw::ApplicationWindow
def initialize(application : Adw::Application)
super(application: application)
pic = Gtk::Picture.new(paintable: MyPicture.new)
self.content = pic
spawn do
sleep 5.seconds
GLib.idle_add do
GC.collect
false
end
end
end
end
class MyPicture < GObject::Object
include Gdk::Paintable
def initialize
super()
end
@[GObject::Virtual]
def do_snapshot(snapshot : Gdk::Snapshot, width : Float64, height : Float64) : Nil
end
end As you can see, it's also independent of ScrolledWindow, GridView etc. Including |
I won't have time to investigate this soon... 😔 |
No worries, take your time! I'll keep adding comments as I narrow the issue down more and more. It's the most I can do, without knowing any C 😔 . Also, I'm not sure whether I'm supposed to open issues here or under GI-Crystal. So there appear to be 2 separate issues here. The first one is probably related to The following example crashes when class MainWindow < Adw::ApplicationWindow
def initialize(application : Adw::Application)
super(application: application)
button = Gtk::Button.new(label: "GC collect")
button.clicked_signal.connect do
GLib.idle_add do
GC.collect
false
end
end
self.content = button
end
end The solution here is very simple: Create a helper constant that keeps the reference to the window alive. KEEP_ALIVE = [] of GObject::Object
class MainWindow < Adw::ApplicationWindow
def initialize(application : Adw::Application)
super(application: application)
KEEP_ALIVE << self
# rest of the code
end
end Huge thanks to BlobCodes for discovering this. For the other GC problem, I will open another issue, as that's a bit more esoteric. |
Hi!
I apologise for the lengthy issue in advance.
The following minimal example of images in a
ListView
in aScrolledWindow
crashes after scrolling a bit.The files are included as a
.zip
for easier local reproducibility.The main idea is lazily loading the images via a custom
Gdk::Paintable
, that only loads when the image is actually shown. AListView
with a few hundred images is otherwise basically unusable because of the constant stutter, load time and astronomical memory usage.window.cr
With the blueprint
Blueprint
The actual error messages are wildly inconsistent, often time I get none at all. But they're generally:
Errors
Video demonstration
Screencast.From.2024-12-21.00-59-19.mp4
Disabling the GC at the beginning with
GC.disable
completely solves the issue. Interestingly, this issue doesn't occur with a fewer number of rows, for example 500. My assumption is that in that case, the GC isn't inclined to trigger yet.I have attached a
valgrind
report as well.valgrind.log
Minimal Example.zip
Big thanks to @BlobCodes. I had no idea what was going on.
Thanks in advance!
The text was updated successfully, but these errors were encountered: