Giter Club home page Giter Club logo

Comments (13)

HinTak avatar HinTak commented on May 26, 2024

You should call FT_Done_Glyph explicitly .

from freetype-py.

jiong3 avatar jiong3 commented on May 26, 2024

That doesn't seem to work, glyph is freed properly anyway (at least with destroy=True) but maybe blyph is not, since the __del__ is commented out? If I uncomment it it crashes.

    # def __del__( self ):
    #     '''
    #     Destroy glyph.
    #     '''
    #     FT_Done_Glyph( cast(self._FT_BitmapGlyph, FT_Glyph) )

from freetype-py.

HinTak avatar HinTak commented on May 26, 2024

Sigh. I meant you need to use FT_Done_Glyph at the end of the loop.

BTW, the destructor __del__ routine has to be wrong (likely the reason that it is commented out) when it does not test for true/falsehood of destroy.

AFAIC, you should clean up and call FT_Done_Glyph if you use destroy=False.

from freetype-py.

jiong3 avatar jiong3 commented on May 26, 2024

No need to "Sigh". Feel free to modify my code sample according to what you think should work.

from freetype-py.

HinTak avatar HinTak commented on May 26, 2024

It is your code and I have no intention of spending much time on it. It is up to you yourself to work out the details.

from freetype-py.

HinTak avatar HinTak commented on May 26, 2024

Btw, to_bitmap also has a destroy= argument. Also, upstream has a FT_Bitmap_Done routine which is not in freetype-py at the moment.

from freetype-py.

HinTak avatar HinTak commented on May 26, 2024

Since upstream FT_Stroke_Done and FT_Bitmap_Done are two different routines, most likely you should think of stroke and bitmap as different and separate.

from freetype-py.

jiong3 avatar jiong3 commented on May 26, 2024

I found another python wrapper for freetype which seems to have better memory management. It releases the bitmaps with FT_Bitmap_Done and only casts the Glyph to BitmapGlyph when needed, which is probably the way to go.

from freetype-py.

HinTak avatar HinTak commented on May 26, 2024

A word of advice: script trying to demonstrate a possible problem should not (1) use rare or non-free data or input, (2) have more than one problem and more than one widely-unrelated problem, (3) too long. For these reasons, it is very unlikely that anybody will try to run your script at all. So do not even try to ask people to "debug your long program". You will simply get very rude response if at all.

from freetype-py.

HinTak avatar HinTak commented on May 26, 2024

On my pull there is new import hook for FT_Bitmap_Done and a lot more of missing Freetype routines :
#52

from freetype-py.

HinTak avatar HinTak commented on May 26, 2024

Here is a 4th problem with your script - it takes about 5 hours to run on my hardware. It is crazy to post example that needs 5 hours to run to see if there is a problem at all ( range(10000000)).

Anyway, here is the correction for the 2nd leak - you are calling freetype wrong - you should be doing this instead - note the byref part and the destroy=True part:

blyph = glyph.to_bitmap(ft.FT_RENDER_MODE_NORMAL, byref(ft.Vector(0, 0)), destroy=True)

Without the byref, the 16-byte ft.Vector(0, 0) occupies both the 8-byte pointer and the destroy= argument, in effect hard-coding destroy=False. Hence adding destroy= afterwards had no effect.

It is a fault that freetype-pydoes not check argument types and sizes as they go through the python-C bridge. In that sense the other python wrapper is better, as the other wrapper would crash and abort if you try to pass wrong types/sizes instead of silently letting you use freetype wrongly. I also see without byrefis more "natural", and in fact how some of the examples are written, so I have added code to auto-detect the wrong way of calling freetype and auto-correct it. I shall push that as an enhancement as some point.

I am still looking at the first leak - but it is another user problem (i.e. your script is poor). Both of the leaks are due to destroy=False. (in the 2nd case, because of the size mis-interpretation of FT_Vector). It is in the freetype documentation that when destroy=False, that's what destroy=False means - you, the user, should clean up (because you want to keep the original). The user's script is responsible for doing a manual destroy. i.e. you are supposed to do something like this:

# make a copy of glyph._FT_Glyph, as it will be changed by glyph.stroke()
original = glyph._FT_Glyph # not correct way of copying
glyph.stroke(stroker, destroy=False)
... 
# do more stuff with the original
...
ft.FT_Done_Glyph(original)

I am still trying to figure out the correct syntax of copying and keeping the original in python. In C, you just do original = glyph._FT_Glyph, but that does not work correctly in python - the copy is also changed on exit from stroke.

Back to the 4th criticism - there is no need to do range(10000000) . You could just do range(1), or just remove the loop. One of the non-standard build options of freetype allows freetype itself to detect memory leaks of user-programs that uses freetype - freetype itself tells you what and where the leaks are, AFTER your program finishes. Hence your program MUST run within reasonable time, certainly not 5 hours, to use that feature!

The first leaks is a few hundred bytes, the 2nd about 1.5k, but if both are on, about 9k per loop (the first destroy=False affects the 2nd). It is just poorly-written, in so many ways.

from freetype-py.

HinTak avatar HinTak commented on May 26, 2024

I have gone through all the freetype-py shipped examples, as well as the rather poor example above, and modified them to be leak-free; however, I do not think the shipped examples should be unnecessarily complicated, nor should they try to be perfect. Consider that the python interpreter itself has a 15MB memory foot print, a 9k leak while it runs is quite acceptable and for the sake of simplicity. So:

  • a bundle of problems I have fixed and improvements I have found while looking at all the examples are added to #52

  • if you don't know the difference between destroy=False and destroy=True, you should just use the latter. destroy=True does not need extra code for memory management. destroy=False needs a bit more code before and after.

  • I have modified the shipped examples to use destroy=True in #52 as they do not need the functionalities offered by destroy=False , AFAIC.

  • I am not pushing any of the detailed memory usage hourse-keep addition to the freetype-py examples out, as I think that would make the examples unnecessarily complicated.

  • my first response is exactly the same as my final response - if you use destroy=False , you should call FT_Done_Glyph explicitly yourself. Your code is 26-line long, and my leak-free version is 47-line long, with 21 of the original lines (plus 2 with destroy=True changed). So I have doubled its length, and added the 4th case destroy=False of glyph.to_bitmap . You want your code to use 5 hours of CPU time without leaking? It is possible - you need to write a lot more house-keeping code - about double its current length. And let me repeat: if you don't know the difference between destroy=False and destroy=True, you should just use the latter. If you use destroy=False , you need more code, and call FT_Done_Glyph explicitly yourself.

A 26-line script which needs to be almost double in size, to 47-lines, to do its job is not a bug - it is incomplete and not yet finished.

from freetype-py.

HinTak avatar HinTak commented on May 26, 2024

This is from https://github.com/ldo/qahirah (same author as the other freetype binding) -

Because it is pure Python, the abstractions it implements are “leaky”.
  As Guido van Rossum has made clear, “We’re all consenting adults here”.

It is possible to write python scripts which track memory usage properly C-style, without leaking a single byte. My collected diffs against the examples do that. But the whole point of using a scripting language is that one does not want to do that. OTOH, if you write a python script that runs for 5 hours, you better write it properly - and it is just that, you script is incomplete, it is missing a lot of memory management code, and you either did not read the documentation, or did not understand it. The meaning of "destroy=False" is what it is - you say you will do your own clean-up and do not want stuff destroyed, and therefore you must add more code to clean-up.

(Since I have a memory-debugging enabled freetype build, I thought I'll have a look at how the other freetype-python binding does, before I throw the build away. that part of the README is not optimistic, but quite understandable and expected).

from freetype-py.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.