Again, dispose problems

Discussion in 'Learning Ruby and RGSSx' started by Napoleon, Jul 21, 2014.

    Tags:
  1. Napoleon

    Napoleon Veteran Veteran

    Messages:
    869
    Likes Received:
    96
    First Language:
    Dutch
    Window_Base:

    #-------------------------------------------------------------------------- # * Reset Font Settings #-------------------------------------------------------------------------- def reset_font_settings change_color(normal_color) p contents.disposed? # False p contents.font # #<Font:0x84c4c78> p contents.font.size # 24 p contents.font.name # "VL Gothic" contents.font.size = 10 # <<<<<< Crash: disposed bitmap contents.font.size = Font.default_size contents.font.bold = Font.default_bold contents.font.italic = Font.default_italic endWhy do I get that error when nothing seems to be disposed?

    I have this code:

    @bmp.font = contents.font...@bmp.dispose # <<<< outcommenting this line will make the crash disappear. But that makes no sense.So I started a fresh project and changed the following method in Window_Message:

    def new_page(text, pos) contents.clear draw_face($game_message.face_name, $game_message.face_index, 0, 0) reset_font_settings pos[:x] = new_line_x pos[:y] = 0 pos[:new_x] = new_line_x pos[:height] = calc_line_height(text) clear_flags ########### MY CODE BELOW ########### a = Bitmap.new(1,1) a.font = contents.font a.dispose endAnd yes this generates the exact same error.

    So wait a minute... Does disposing a bitmap also dispose fonts somehow? Even if they are used in other bitmaps? There is no font.disposed? method.

    I kinda want my font to be the same as the one from the Window_Message but without the crash obviously.

    And this also crashes:

        a = Bitmap.new(1,1)    a.font = contents.font    a.font = a.font.dup    a.disposeI duped it but the original one is still disposed. Almost as if the "a" bitmap now holds 2 fonts and still disposes both?

    This also crashes:

        a = Bitmap.new(1,1)    a.font = contents.font    a.font = Font.new('Arial', 24)    a.disposeSo I assign another font to it instead and still it 'disposes' the other font somehow?

    This does not crash:

        a = Bitmap.new(1,1)    #a.font = contents.font    a.font = Font.new('Arial', 24)    a.disposeNow isn't that weird?
     
    Last edited by a moderator: Jul 22, 2014
    #1
  2. Evgenij

    Evgenij Veteran Veteran

    Messages:
    349
    Likes Received:
    100
    First Language:
    German
    Primarily Uses:
    N/A
    Hmm I dont know exactly but I think this shouldn't crash:

    Code:
        a = Bitmap.new(1,1)    a.font = contents.font.dup    a.dispose
     
    #2
  3. Napoleon

    Napoleon Veteran Veteran

    Messages:
    869
    Likes Received:
    96
    First Language:
    Dutch
    Indeed that doesn't crash. But now I have 2 fonts that I have to synchronize manually every time I use it. Not too great for performance to dup it so much. Plus it just makes no sense that bitmaps also dispose the Font somehow. This is not documented anywhere. The Garbage Collector should dispose the font, not the bitmap that 'disposes' the font.
     
    Last edited by a moderator: Jul 22, 2014
    #3
  4. FenixFyreX

    FenixFyreX Fire Deity Veteran

    Messages:
    434
    Likes Received:
    307
    Location:
    A Volcano Somewhere
    First Language:
    English
    That is really peculiar...


    I think that this is done in the internal workings of RGSS, like Tilemap, or Sprite. freefont is the C library they use, and with C code comes memory management. My guess is that instead of setting up a free() method for fonts and accounting for every font instance (free() is the c method Ruby's GC calls when an object is marked for disposal), they just threw it into Bitmap's free() method to simplify their lives...


    I've done a few tests, and no matter how many times you change the bitmap's font; if you dispose the bitmap after attaching any font to it, that font will be disposed of as well. I even alias Bitmap#dispose to attempt to stem the problem by removing the font from the bitmap, but it seems there's an internal list of attached fonts kept somewhere out of reach.


    I'll keep poking around to try and help out. In the meantime, you could always setup a method in Game_Temp that modifies a font to your liking, like Game_Temp#setup_napoleon_scriptname_font, and alias create_contents in the window classes you need to alter to setup the contents font as it is created...but that's a short term fix, really.


    I assume if you create a Font instance and do not attach it to a bitmap, it'll create a memory leak. If it does not, then eB! programmers were just crazy for implementing this weird behavior. It would make more sense to add a Font#disposed? method, etc.
     
    Last edited by a moderator: Jul 22, 2014
    #4
  5. Napoleon

    Napoleon Veteran Veteran

    Messages:
    869
    Likes Received:
    96
    First Language:
    Dutch
    Font has no dispose method so if it causes any kind of leak then Ace needs a serious patch.

    9999999.times do a = Font.new('Arial', 30) GC.startendDoes not increase the memory usage so no leak.

    Maybe a font is actually a bitmap-font internally? That would explain the disposed bitmap error for another bitmap that is not disposed at all.
     
    #5
  6. cremnophobia

    cremnophobia Veteran Veteran

    Messages:
    194
    Likes Received:
    80
    Did you really want to use Font with an uppercase F here? You're calling Module#name. This method name is somewhat unfortunate. Maybe it should have been __name__.

    Perhaps you've only mixed up the terminology, but the programmer has to dispose objects. The GC just manages memory. And you can't dispose fonts. It isn't a graphic object!


    I'm not good at explaining, but I'll try and it seems you've already figured out some things on your own.

    b = Bitmap.new(1, 1)This creates a Bitmap and a Font object (and some other unimportant ones). The Font one has a hidden instance variable that references the Bitmap object. The Bitmap hone as one, too. “Normal” Font objects don't have that, BTW.
    There is also this:

    b.font = f1 = f2 = Font.new('Arial', 24)p f1.equal?(f2)p f1.equal?(b.font)Surprising result, isn't it?

    More very weird behavior:

    def m b = Bitmap.new(1, 1) f = b.font.dup b.dispose fendf = mf.size = 24The reason behind the exception is that the last line (internally) sends font= to the bitmap.Yes, the bitmap is disposed, but until the font is GC'd it still exists! That's a memory leak.

    This works:

    Code:
    def m  b = Bitmap.new(1, 1)  f = Font.new  f.name = b.font.name  f.size = b.font.size  # etc. (Sadly Font doesn't have #set, but you can always write your own!)  b.dispose  fendf = mf.size = 24
    And the same applies to other RGSS graphic objects and their attributes like color or rect. If you really want to reuse such an object, create a new one instead.
     
    Last edited by a moderator: Jul 22, 2014
    #6
    Napoleon and Evgenij like this.
  7. FenixFyreX

    FenixFyreX Fire Deity Veteran

    Messages:
    434
    Likes Received:
    307
    Location:
    A Volcano Somewhere
    First Language:
    English
    If everything you've described is true (and it is, I've tested it all just now), then can't he simply alias Bitmap#font= to return false if it's disposed, like so?


    <removed_code>


    So a bitmap's font object -never- changes, only it's properties change, according to cremno's eql? example. Therefore, it makes sense to only duplicate it's properties, so I'd recommend making a Font#set, like cremno said. That would solve the problems without monkeypatching the default classes.
     
    Last edited by a moderator: Jul 22, 2014
    #7
  8. Napoleon

    Napoleon Veteran Veteran

    Messages:
    869
    Likes Received:
    96
    First Language:
    Dutch
    Sorry I already edited the Font (capital F) variable out of my post because I saw my mistake there after some more debugging.

    Yes you are right I mixed the terminologies.

    b = Bitmap.new(1, 1)b.font = f1 = f2 = Font.new('Arial', 24)p f1.equal?(f2) # truep f1.equal?(b.font) # falseHuh? I don't understand that part. Either all true or all false... At least that I would expect.

    Re-using is not always an option. Sometimes you want the reference or pointer. But Ruby doesn't support pointer arithmetic (**** Ruby) like C or C# does so a reference is the only way. Now combine that with this 'weird' behavior and good luck.

    I still don't understand why this code bugs:

    a = Bitmap.new(1,1) a.font = contents.font a.font = Font.new('Arial', 24) # I assigned a new font now. Why is the previous font STILL BEING USED by that bitmap when disposing it? Does it have an array of Fonts and then kills 'em all? a.disposeI even tried assigning the old font to another bitmap that is not disposed but it had no effect.

    I'd like 1 Font object with 2 references/pointers. Pointers are out of the question so references it shall be.

    Alternatively I have to add new functionality to Font to create duplicates and whenever one of those duplicates is changed, all of the duplicates are changed. But this is so messy and performs crap.

    I also don't understand why they implemented it like this at all. Why is there no option like:

    Code:
    a = Bitmap.new(1,1)a.dispose_font = false
     
    Last edited by a moderator: Jul 22, 2014
    #8
  9. cremnophobia

    cremnophobia Veteran Veteran

    Messages:
    194
    Likes Received:
    80
    Because in line 2 the value of the hidden instance variable of contents.font gets changed from contents to a. Assigning attributes of RGSS graphic objects is … very nasty. I guess more appropiate words are forbidden on this site.

    Here's a public domain Font#set implementation:

    class Font def set(font) if !font.is_a?(Font) fail(TypeError, "wrong argument type #{font.class} (expected Font)") end self.name = font.name self.size = font.size self.bold = font.bold self.italic = font.italic self.outline = font.outline self.shadow = font.shadow self.color.set(font.color) self.out_color.set(font.out_color) endendI guess the best solution for your problem is never using a setter method, but rather #set, if it's available. This should work now:

    a = Bitmap.new(1,1) a.font.set(contents.font) a.font.set(Font.new('Arial', 24)) a.dispose
    I repeat: Fonts can't be disposed.
     
    Last edited by a moderator: Jul 22, 2014
    #9
  10. Napoleon

    Napoleon Veteran Veteran

    Messages:
    869
    Likes Received:
    96
    First Language:
    Dutch
    I usually use the word "dispose" for any form of cleanup in RGSS. So let me rephrase:

    a = Bitmap.new(1,1)a.retain_font = true # does do NOTHING to the font when the dispose() is called on the bitmapBecause obviously even though a font is not disposed, something is done to it by the bitmap to render it unusable for other bitmaps. Almost as if the font is embedded into the bitmap itself. The font still has a name, size, etc. But as soon as you use it on another bitmap, crash. It's not collected by the GC yet (and shouldn't because there are more references to it) and still crashes.

    Why did they implement it like that? I don't understand why they can't just have an attr_accessor called Font. Nothing special. Why some hidden instance variable or hidden setter that does god knows what. No documentation + closed source + Ruby combined drives me nuts sometimes, wasting lots of time. It's probably me but still... Not being able to share a Font object between 2 Bitmaps is like...ugh...

    I guess I can't overwrite the Bitmap.dispose() method somehow to ignore the font?

    Update:

    If this also applies to colors then:

    assigning Font.default_out_color to a bitmap is gonna be fun:

    a = Font.default_out_colorb = Font.default_out_colorp a.object_id == b.object_id # trueSo when you use

    my_bitmap.my_font.out_color = Font.default_out_color # You are screwed if your code looks like this. Because it will then bug just like the Font references.I'm pretty sure that if this theory is true that this is a bug.
     
    Last edited by a moderator: Jul 22, 2014
    #10
  11. cremnophobia

    cremnophobia Veteran Veteran

    Messages:
    194
    Likes Received:
    80
    Disposing is not the problem. The idiotic setter methods and hidden ivars are.

    RE your update: No, this is only true for attributes of graphic objects. E.g., for this Color object:

    Code:
    Bitmap.new(1, 1).font.out_color
     
    Last edited by a moderator: Jul 22, 2014
    #11

Share This Page