Skip to content
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

Memory leak with VImage::text() , vips-8.8.4 #1508

Closed
uint128 opened this issue Dec 21, 2019 · 7 comments
Closed

Memory leak with VImage::text() , vips-8.8.4 #1508

uint128 opened this issue Dec 21, 2019 · 7 comments
Labels

Comments

@uint128
Copy link

uint128 commented Dec 21, 2019

Firstly , thanks for the amazing library!
I am using vips-8.8.4.
When I using VImage::text() to draw some cjk unicode text to new image, the resident memory by the process increases rapidly, and never decrease.
For the example in attach, the process used about 5G memory.
Another strange point is that the resident memory by the process can go much bigger than the total used memory show by top command, as showing in the screen shot below:

2019-12-21 12-36-12 screen shot

#include <iostream>
#include <string>
#include <fstream>
#include <list>
#include <boost/algorithm/string/trim.hpp>
#include <boost/lexical_cast.hpp>
#include <vips/vips8>
#include <vips/VImage8.h>

using namespace std;
using namespace boost;
using namespace vips;

int main(int argc, char* argv[] ){
  if (VIPS_INIT ("vips_test1")){ 
    vips_error_exit ("can not init vips");
	}


	string font_str = "AR PL UMing CN " + boost::lexical_cast<string>(20) + "px";
	ifstream ifs("text_to_draw.txt");
	list<string> str_ls;
	string line;
	while(getline(ifs, line)){
		trim(line);
		if( line.empty() ){
			continue;
		}
		str_ls.push_back(line);
	}

	for(int i=0; i < 10 ; i++ ){
		for(auto& line : str_ls ){
			char* escape = g_markup_escape_text(line.c_str(), -1);
			std::string escape_str(escape);
			g_free(escape);
			int width = rand()%200 + 100;
			int height = rand()%200 + 100;
			auto opt = VImage::option ()->
				set ("width", width)->
				set ("height", height)->
				set ("font", font_str.c_str());
			auto tmp_p = escape_str.c_str();
			VImage t_img = VImage::text(tmp_p, opt);
		}
	}

	// to watch the memory
	string tmp;
	cin >> tmp;
	return 0;
}

text_to_draw.txt

@jcupitt
Copy link
Member

jcupitt commented Dec 21, 2019

Wow, I see terrible memory behaviour here too.

Thanks, I'll investigate.

@jcupitt jcupitt added the bug label Dec 21, 2019
@jcupitt
Copy link
Member

jcupitt commented Dec 21, 2019

I see the problem with this simpler program:

/* compile with 
 *
 * g++ -g -Wall text.cpp `pkg-config vips-cpp --cflags --libs`
 */

#include <iostream>
#include <string>
#include <vips/vips8>

using namespace std;
using namespace vips; 

int 
main (int argc, char* argv[]) 
{       
        if (VIPS_INIT ("vips_test1"))
                vips_error_exit ("can not init vips");

        // turn off the operation cache, or we'll just run the text once
        vips_cache_set_max (0);

        //string txt = "积蓄了眼睛的疲劳使之恢复精神! ・舒适的蒸汽持续约12分钟";
        string txt = "Hello, world!";

        for (int i = 0; i < 1000; i++) {
                cout << "iteration " << i << endl;
                        
                auto tmp_p = txt.c_str();
                VImage t_img = VImage::text(tmp_p, VImage::option ()->
                        set ("width", 500)->
                        set ("height", 500));
        }

        // pause to watch the memory
        string tmp;
        cin >> tmp;
        return 0;
}

It gets to 2gb of memory by about 500 iterations with the English text (and by 50 iterations with the Chinese text).

@uint128
Copy link
Author

uint128 commented Dec 21, 2019

I am currently located to the stack:
libvips/create/text.c:369
if( vips_text_autofit( text ) )
libvips/create/text.c:299
if( vips_text_get_extents( text, &extents ) )
libvips/create/text.c:190
pango_layout_get_pixel_extents( text->layout,
it seems like the function vips_text_get_extents( ) using remarkable memory, and it is in a long running loop.
inside vips_text_get_extents( ) there is a calling to pango_layout_get_pixel_extents( ).

@jcupitt
Copy link
Member

jcupitt commented Dec 21, 2019

Yes, it looks like a Pango leak, or perhaps I'm misusing pango_layout_get_pixel_extents().

I'm planning to build pango myself and look in there.

jcupitt added a commit that referenced this issue Dec 21, 2019
We were not unreffing PangoLayout. Thank you uint128!

See #1508
@jcupitt
Copy link
Member

jcupitt commented Dec 21, 2019

Huh it was really simple, there was just a missing unref. Your example runs in a steady and small amount of memory for me now.

Could you test with this patch?

@uint128
Copy link
Author

uint128 commented Dec 22, 2019

I have tested with the patch. The example and my other code works fine.
Thank you a lot. You have saved me a lot of trouble.

@jcupitt
Copy link
Member

jcupitt commented Dec 22, 2019

That's great, thank you for reporting and testing this issue.

This fix will be in 8.9.0, due in a few days.

@jcupitt jcupitt closed this as completed Dec 22, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants