Hi guys,

I'm trying to use the random number generator as part of the GSL library and it is working fine for a few hundred 'rounds' of my code (it is used quite a few times per round) but then i get an error message in the command window:

gsl: rng.c:46: ERROR: failed to allocate space for rng state
Default GSL error handler invoked.

A quick look at the rng.c shows that this is an error from the gsl_rng_alloc part (see bottom)and this is what I can find about that function on that topic:

— Function: gsl_rng * gsl_rng_alloc (const gsl_rng_type * T)
This function returns a pointer to a newly-created instance of a random number generator of type T. For example, the following code creates an instance of the Tausworthe generator,

          gsl_rng * r = gsl_rng_alloc (gsl_rng_taus);
If there is insufficient memory to create the generator then the function returns a null pointer and the error handler is invoked with an error code of GSL_ENOMEM.

But unfortunately I don't quite understand what it all means - I'm quite new to all this, as is probably clear...

Could you please help explain what is happening here and possible way of stopping this happening?

I've tried changing the size and way of declaring the seed, putting the definition just once at the start of the code and then at the start of each loop where it is used and it seems to make no difference.

Any help very much appreciated.

If there's anything else I've left out that you would need to know, please just ask.

Thanks!
______________________________________________

#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_rng.h>

gsl_rng *
gsl_rng_alloc (const gsl_rng_type * T)
{

  gsl_rng *r = (gsl_rng *) malloc (sizeof (gsl_rng));

  if (r == 0)
    {
      GSL_ERROR_VAL ("failed to allocate space for rng struct",
                        GSL_ENOMEM, 0);
    };

  r->state = malloc (T->size);

  if (r->state == 0)
    {
      free (r);         /* exception in constructor, avoid memory leak */

      GSL_ERROR_VAL ("failed to allocate space for rng state",
                        GSL_ENOMEM, 0);
    };

  r->type = T;

  gsl_rng_set (r, gsl_rng_default_seed);        /* seed the generator */

  return r;
}

Dani AI

Generated

Short summary: that GSL error is the library telling the allocator for the RNG internal state failed (GSL_ENOMEM). In practice it almost always means repeated allocations without matching frees (heap exhaustion) or another memory leak that eventually makes malloc fail. As discovered, freeing the generator removed the failure; and were right to point at repeated creation as the usual cause.

Practical checklist and fixes:

  • Allocate once and reuse. Create a single RNG (or one per thread) and call it many times rather than allocating a new generator on every iteration.
  • Free on every path. Every code path that runs after an allocation must free the RNG. Early exits, error branches and goto jumps are the usual places a free gets missed; RAII (destructor-based cleanup) or a smart pointer with a custom deleter avoids this class of bug.
  • Detect leaks with tools. Run Valgrind, AddressSanitizer or similar to find where allocations are not freed and to confirm the RNG state allocations are the culprits.
  • Seed once. Seeding repeatedly inside tight loops is unnecessary; set the seed once when the generator is created.
  • Threading caution. GSL RNGs are not implicitly thread-safe — give each thread its own generator or protect access with a lock.

Note for : in the shown ransac_xform flow there is an RNG allocation and a free at function end; verify every early-return/goto path passes through the free (or switch to RAII), or move the RNG to outer scope and pass it in. For new C++ projects, consider modern C++ facilities (C++11 <random> or Boost.Random) which avoid manual malloc/free of RNG state.

Recommended Answers

All 4 Replies

Hi guys,

I'm trying to use the random number generator as part of the GSL library and it is working fine for a few hundred 'rounds' of my code (it is used quite a few times per round) but then i get an error message in the command window:

gsl: rng.c:46: ERROR: failed to allocate space for rng state
Default GSL error handler invoked.

Please post the part of your code that is actually generating the random numbers.

My guess is that you're creating a new generator every time you need a random number, and you're not destroying it after you're done. If that's the case, the allocator will happily reserve whatever amount of space it needs for each generator, and eventually you'll run out of memory.

Ahh, good old bug-riddled GSL! If I had a dime for every bug in GSL, I'd be a rich man.

Obviously, the problem is that you run out of memory. Meaning you have a memory leak in a loop. If you call the above function within a loop without freeing the memory of both the rng and its state, you'll eventually run out of memory.

I hope that you understand how random number generators work and why you only need to seed it once. In theory at least, you shouldn't need to recreate a new random number generator more than once. I'm not familiar with GSL's rng code, but if it is logical, then it shouldn't require you to create the rng more than once, but again, GSL is not known for being logical or well programmed, quite to the contrary.

The real answer to your problem is to use the random number generators provided by the C++ standard <random> library or by Boost.Random. Which are both virtually identical and very feature-rich.

Thanks for your help guys. Yes, I've solved it now. I was using it in a function that was being repeatedly called and therefore constantly creating a new generator. I restructured my code to mostly fix this and found:

— Function: void gsl_rng_free (gsl_rng * r)
This function frees all the memory associated with the generator r.

to free up the memory. Works perfect now!

Hi,
I met the same problem when I read someother's codes. But unfortunately, I can't solve it.
The function is:
CvMat* ransac_xform( struct feature* features, int n, int mtype,
ransac_xform_fn xform_fn, int m, double p_badxform,
ransac_err_fn err_fn, double err_tol,
struct feature*** inliers, int* n_in )
{
struct feature** matched, ** sample, ** consensus, ** consensus_max = NULL;
struct ransac_data* rdata;
CvPoint2D64f* pts, * mpts;
CvMat* M = NULL;
gsl_rng* rng;
double p, in_frac = RANSAC_INLIER_FRAC_EST;
int i, nm, in, in_min, in_max = 0, k = 0;

nm = get_matched_features( features, n, mtype, &matched );
if( nm < m )
{
    fprintf( stderr, "Warning: not enough matches to compute xform, %s" \
        " line %d\n", __FILE__, __LINE__ );
    goto end;
}

/* initialize random number generator */
rng = gsl_rng_alloc( gsl_rng_mt19937 );
gsl_rng_set( rng, time(NULL) );

in_min = calc_min_inliers( nm, m, RANSAC_PROB_BAD_SUPP, p_badxform );
p = pow( 1.0 - pow( in_frac, m ), k );
i = 0;
while( p > p_badxform )
{
    sample = draw_ransac_sample( matched, nm, m, rng );
    extract_corresp_pts( sample, m, mtype, &pts, &mpts );
    M = xform_fn( pts, mpts, m );
    if( ! M )
        goto iteration_end;
    in = find_consensus( matched, nm, mtype, M, err_fn, err_tol, &consensus);
    if( in > in_max )
    {
        if( consensus_max )
            free( consensus_max );
        consensus_max = consensus;
        in_max = in;
        in_frac = (double)in_max / nm;
    }
    else
        free( consensus );
    cvReleaseMat( &M );

iteration_end:
release_mem( pts, mpts, sample );
p = pow( 1.0 - pow( in_frac, m ), ++k );
}

/* calculate final transform based on best consensus set */
if( in_max >= in_min )
{
    extract_corresp_pts( consensus_max, in_max, mtype, &pts, &mpts );
    M = xform_fn( pts, mpts, in_max );
    in = find_consensus( matched, nm, mtype, M, err_fn, err_tol, &consensus);
    cvReleaseMat( &M );
    release_mem( pts, mpts, consensus_max );
    extract_corresp_pts( consensus, in, mtype, &pts, &mpts );
    M = xform_fn( pts, mpts, in );
    if( inliers )
    {
        *inliers = consensus;
        consensus = NULL;
    }
    if( n_in )
        *n_in = in;
    release_mem( pts, mpts, consensus );
}
else if( consensus_max )
{
    if( inliers )
        *inliers = NULL;
    if( n_in )
        *n_in = 0;
    free( consensus_max );
}

gsl_rng_free( rng );

end:
for( i = 0; i < nm; i++ )
{
rdata = feat_ransac_data( matched[i] );
matched[i]->feature_data = rdata->orig_feat_data;
free( rdata );
}
free( matched );
return M;
}

I didn't find the function gsl_rng_alloc that was repeatlly called, and the function ransac_xform is only called by the main function:

int main( int argc, char** argv )
{
IplImage* img1, * img2, * stacked;
struct feature* feat1, * feat2, * feat;
struct feature** nbrs;
struct kd_node* kd_root;
CvPoint pt1, pt2;
double d0, d1;
int n1, n2, k, i, m = 0;
img1 = cvLoadImage( img1_file, 1 );
if( ! img1 )
fatal_error( "unable to load image from %s", img1_file );
img2 = cvLoadImage( img2_file, 1 );
if( ! img2 )
fatal_error( "unable to load image from %s", img2_file );
stacked = stack_imgs( img1, img2 );

fprintf( stderr, "Finding features in %s...\n", img1_file );
n1 = sift_features( img1, &feat1 );
fprintf( stderr, "Finding features in %s...\n", img2_file );
n2 = sift_features( img2, &feat2 );
kd_root = kdtree_build( feat2, n2 );
for( i = 0; i < n1; i++ )
{
    feat = feat1 + i;
    k = kdtree_bbf_knn( kd_root, feat, 2, &nbrs, KDTREE_BBF_MAX_NN_CHKS );
    if( k == 2 )
    {
        d0 = descr_dist_sq( feat, nbrs[0] );
        d1 = descr_dist_sq( feat, nbrs[1] );
        if( d0 < d1 * NN_SQ_DIST_RATIO_THR )
        {
            pt1 = cvPoint( cvRound( feat->x ), cvRound( feat->y ) );
            pt2 = cvPoint( cvRound( nbrs[0]->x ), cvRound( nbrs[0]->y ) );
            pt2.y += img1->height;
            cvLine( stacked, pt1, pt2, CV_RGB(255,0,255), 1, 8, 0 );
            m++;
            feat1[i].fwd_match = nbrs[0];
        }
    }
    free( nbrs );
}

fprintf( stderr, "Found %d total matches\n", m );
cvNamedWindow( "Matches", 1 );
cvShowImage( "Matches", stacked );
cvWaitKey( 0 );


/* 
UNCOMMENT BELOW TO SEE HOW RANSAC FUNCTION WORKS

Note that this line above:

feat1[i].fwd_match = nbrs[0];

is important for the RANSAC function to work.
*/

{
    CvMat* H;
    H = ransac_xform( feat1, n1, FEATURE_FWD_MATCH, lsq_homog, 4, 0.01,
        homog_xfer_err, 3.0, NULL, NULL );

    if( H )
    {
        IplImage* xformed;
        xformed = cvCreateImage( cvGetSize( img2 ), IPL_DEPTH_8U, 3 );
        cvWarpPerspective( img1, xformed, H, 
            CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS,
            cvScalarAll( 0 ) );
        cvNamedWindow( "Xformed", 1 );
        cvShowImage( "Xformed", xformed );
        cvWaitKey( 0 );
        cvReleaseImage( &xformed );
        cvReleaseMat( &H );
    }
}


cvReleaseImage( &stacked );
cvReleaseImage( &img1 );
cvReleaseImage( &img2 );
kdtree_release( kd_root );
free( feat1 );



free( feat2 );
return 0;

}

Any help very much appreciated.
Thanks!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.