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

pixSauvolaBinarize keep crashing #272

Closed
thachvupham opened this issue Nov 22, 2018 · 26 comments
Closed

pixSauvolaBinarize keep crashing #272

thachvupham opened this issue Nov 22, 2018 · 26 comments

Comments

@thachvupham
Copy link

thachvupham commented Nov 22, 2018

javacpp version : '1.4.3'

I have run this code with multiple threads and it always crashes after few hours:

import org.bytedeco.javacpp.lept.PIX;
import org.bytedeco.javacv.LeptonicaFrameConverter;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.datavec.image.data.ImageWritable;
import static org.bytedeco.javacpp.lept.*;

public BufferedImage binarize(ImageWritable image, float factor) {
        LeptonicaFrameConverter leptonicaFrameConverter = new LeptonicaFrameConverter();
        PIX pix = leptonicaFrameConverter.convert(image.getFrame());
        PIX pixTmp = null;
        PIX binarizedPix = new PIX();
        pixSauvolaBinarize(pix, 14, factor, 1, pixTmp, pixTmp, pixTmp, binarizedPix);
        BufferedImage bufferedImage = fromBinarizedPix(binarizedPix);
   	binarizedPix.destroy();
        return bufferedImage;
}
private BufferedImage fromBinarizedPix(PIX pix) {
        LeptonicaFrameConverter leptonicaFrameConverter = new LeptonicaFrameConverter();    
        return new Java2DFrameConverter().convert(leptonicaFrameConverter.convert(pix));  
}

hs_err_pid.log:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f10f630cc8c, pid=345960, tid=0x00007f10ea4f9700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_131-b11) (build 1.8.0_131-b11)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [liblept.so.5+0x1e9c8c]
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

---------------  T H R E A D  ---------------

Current thread (0x00007f0c94001000):  JavaThread "ForkJoinPool.commonPool-worker-50" daemon [_thread_in_native, id=347499, stack(0x00007f10ea3f9000,0x00007f10ea4fa000)]

siginfo: si_signo: 11 (SIGSEGV), si_code: 1 (SEGV_MAPERR), si_addr: 0x0000000004b36890

Registers:
RAX=0x0000000004b36890, RBX=0x0000000000000072, RCX=0x0000000000000000, RDX=0xffffffffffdcdf27
RSP=0x00007f10ea4f8110, RBP=0x00007f10ea4f81e0, RSI=0x0000000000000d48, RDI=0x00007f08e2f28590
R8 =0x0000000000000d50, R9 =0x0000000000000189, R10=0x000000000000007c, R11=0x00007f1341f64cc8
R12=0x00000000000001aa, R13=0x0000000000000189, R14=0x0000000000000800, R15=0x00000000000001c8
RIP=0x00007f10f630cc8c, EFLAGS=0x0000000000010202, CSGSFS=0x0000000000000033, ERR=0x0000000000000004
  TRAPNO=0x000000000000000e

...

Stack: [0x00007f10ea3f9000,0x00007f10ea4fa000],  sp=0x00007f10ea4f8110,  free space=1020k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [liblept.so.5+0x1e9c8c]
C  [liblept.so.5+0x1e7d1c]  rasteropLow+0x239
C  [liblept.so.5+0x1e6a47]  pixRasterop+0x247
C  [liblept.so.5+0x16bb96]  pixAddBorderGeneral+0x2f4
C  [liblept.so.5+0x16c0b3]  pixAddMirroredBorder+0xe4
C  [liblept.so.5+0x656af]  pixSauvolaBinarize+0x25a
C  [libjnilept.so+0x13bfce]  Java_org_bytedeco_javacpp_lept_pixSauvolaBinarize__Lorg_bytedeco_javacpp_lept_00024PIX_2IFILorg_bytedeco_javacpp_lept_00024PIX_2Lorg_bytedeco_javacpp_lept_00024PIX_2Lorg_bytedeco_javacpp_lept_00024PIX_2Lorg_bytedeco_javacpp_lept_00024PIX_2+0x31e

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
J 5531  org.bytedeco.javacpp.lept.pixSauvolaBinarize(Lorg/bytedeco/javacpp/lept$PIX;IFILorg/bytedeco/javacpp/lept$PIX;Lorg/bytedeco/javacpp/lept$PIX;Lorg/bytedeco/javacpp/lept$PIX;Lorg/bytedeco/javacpp/lept$PIX;)I (0 bytes) @ 0x00007f132dc438f3 [0x00007f132dc43840+0xb3]

...

I have also tried with v1.4.1 and 1.4.2 without success.

@saudet
Copy link
Member

saudet commented Nov 22, 2018 via email

@thachvupham
Copy link
Author

So this "binarizedPix.destroy();" doens't free the allocated memory?

@saudet
Copy link
Member

saudet commented Nov 22, 2018 via email

@thachvupham
Copy link
Author

thachvupham commented Nov 22, 2018

Ok, thanks. What is the correct way to free the memory then? pixDestroy()?

@saudet
Copy link
Member

saudet commented Nov 22, 2018 via email

@thach12345
Copy link

Still crashing with pixDestroy()..

@saudet
Copy link
Member

saudet commented Nov 22, 2018

Could you create a small standalone program to reproduce the crash?

@saudet
Copy link
Member

saudet commented Nov 22, 2018

BTW, since we're not using the PIX you're allocating, we should probably initialize it to null:

    PIX binarizedPix = new PIX(null);
    pixSauvolaBinarize(pix, 14, factor, 1, null, null, null, binarizedPix);
    // do something with binarizedPix
    pixDestroy(binarizedPix);

@thachvupham
Copy link
Author

thachvupham commented Nov 23, 2018

Here is a program which crashes (after 10s running on my mac):

package test;
import static org.bytedeco.javacpp.lept.pixSauvolaBinarize;
import static org.bytedeco.javacpp.lept.pixDestroy;

import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import static java.util.stream.Collectors.toList;

import org.bytedeco.javacpp.lept.PIX;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.javacv.LeptonicaFrameConverter;
import org.datavec.image.data.ImageWritable;
import org.datavec.image.loader.NativeImageLoader;

public class SauvolaTester {

    public static void main(String[] args) throws Exception {
        NativeImageLoader originalImageLoader = new NativeImageLoader();
        ImageWritable originalImage = originalImageLoader.asWritable(new File(args[0]));

        List<ImageWritable> images = new ArrayList<>();
        for (int i = 0; i < 8; i++) {
            images.add(originalImage);
        }

        int count = 0;
        while (true) {
            images.parallelStream().map(s -> binarize(s, 0.4f)).collect(toList());
            count++;
            if (count % 10 == 0) {
                System.out.println(count + " done.");
            }
        }
    }

    private static BufferedImage binarize(ImageWritable image, float factor) {
        LeptonicaFrameConverter leptonicaFrameConverter = new LeptonicaFrameConverter();

        PIX pix = leptonicaFrameConverter.convert(image.getFrame().clone());
        //PIX pixTmp = null;
        PIX binarizedPix = new PIX(null);
        pixSauvolaBinarize(pix, 14, factor, 1, null, null, null, binarizedPix);

        BufferedImage result = fromBinarizedPix(binarizedPix);

        pixDestroy(binarizedPix);

        return result;
    }

    private static BufferedImage fromBinarizedPix(PIX pix) {
        LeptonicaFrameConverter leptonicaFrameConverter = new LeptonicaFrameConverter();
        return new Java2DFrameConverter().convert(leptonicaFrameConverter.convert(pix));
    }
}

gradle:

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'application'
sourceCompatibility = 1.8
group = 'com.test.tester'
mainClassName = "test.SauvolaTester"
allprojects {
  group = 'com.test.tester'
        
  repositories {
    mavenCentral()
  }

  eclipse {
    classpath {
      // customizing the classes output directory:
      defaultOutputDir = file('build-eclipse')

      // default settings for dependencies sources/javadoc download:
      downloadSources = true
      downloadJavadoc = false
        
      file {
        //closure executed after .project content is loaded from existing file
        //and after gradle build information is merged
        whenMerged { classpath ->
          classpath.entries.removeAll { entry -> entry.path.endsWith('.bin') }
        }
      }
    }
  }   
  
  dependencies {
    compile group: 'org.deeplearning4j', name: 'deeplearning4j-core', version: '1.0.0-beta2'
    compile group: 'org.deeplearning4j', name: 'deeplearning4j-nlp', version: '1.0.0-beta2'
    compile group: 'org.bytedeco', name: 'javacpp', version: '1.4.2'
    compile group: 'org.bytedeco', name: 'javacv-platform', version: '1.4.2'
  }
}

lena_gray

@thachvupham
Copy link
Author

thachvupham commented Nov 23, 2018

hs_err_pid.log:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x0000000115eb42c9, pid=20025, tid=22787
#
# JRE version: Java(TM) SE Runtime Environment (8.0_51-b16) (build 1.8.0_51-b16)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.51-b03 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# C  [liblept.5.dylib+0x1b2c9]  pixApplyLocalThreshold+0x259
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

@saudet
Copy link
Member

saudet commented Nov 23, 2018

NativeImageLoader is just like FrameConverter, it holds buffers internally, so you'd need to call clone() before adding the images to the list. That should fix the crash. Let me know if that doesn't fix everything though.

@saudet saudet closed this as completed Nov 23, 2018
@thachvupham
Copy link
Author

thachvupham commented Nov 23, 2018

Still crashing when I changed the main method to this:

public static void main(String[] args) throws Exception {
        List<ImageWritable> images = new ArrayList<>();
        for (int i = 0; i < 8; i++) {
            NativeImageLoader imageLoader = new NativeImageLoader();
            ImageWritable image = imageLoader.asWritable(new File(args[0]));
            images.add(image);
        }

        int count = 0;
        while (true) {
            images.parallelStream().map(s -> binarize(s, 0.4f)).collect(toList());
            
            count++;
            if (count % 100 == 0) {
                System.out.println(count + " done." );
            }
        }
    }

@thachvupham
Copy link
Author

By the way it doesn't crash if I change binarize method to synchronized, but this is what I dont want because no multiple binarization operations can be done in parallel then.

@saudet
Copy link
Member

saudet commented Nov 23, 2018 via email

@thachvupham
Copy link
Author

I think this image.getFrame().clone() is already done inside binarize() method:

PIX pix = leptonicaFrameConverter.convert(image.getFrame().clone());

Anyway, I changed the program to

public static void main(String[] args) throws Exception {
        NativeImageLoader imageLoader = new NativeImageLoader();
        ImageWritable image = imageLoader.asWritable(new File(args[0]));
        
        List<Frame> images = new ArrayList<>();
        for (int i = 0; i < 8; i++) {
            images.add(image.getFrame().clone());
        }

        int count = 0;
        while (true) {
            images.parallelStream().map(s -> binarize(s, 0.4f)).collect(toList());
            count++;
            if (count % 100 == 0) {
                System.out.println(count + " done." );
            }
        }
    }

    private static BufferedImage binarize(Frame image, float factor) {
        LeptonicaFrameConverter leptonicaFrameConverter = new LeptonicaFrameConverter();

        PIX pix = leptonicaFrameConverter.convert(image.clone());
        PIX binarizedPix = new PIX(null);
        pixSauvolaBinarize(pix, 14, factor, 1, null, null, null, binarizedPix);

        BufferedImage result = fromBinarizedPix(binarizedPix);

        pixDestroy(binarizedPix);

        return result;
    }

    private static BufferedImage fromBinarizedPix(PIX pix) {
        LeptonicaFrameConverter leptonicaFrameConverter = new LeptonicaFrameConverter();
        return new Java2DFrameConverter().convert(leptonicaFrameConverter.convert(pix));
    }

but it doesn't help.

@saudet
Copy link
Member

saudet commented Nov 23, 2018 via email

@saudet
Copy link
Member

saudet commented Nov 23, 2018 via email

@thachvupham
Copy link
Author

I tried to remove second image.clone() and it doesn't help.

When I didn't use NativeImageLoader and replaced it by pixRead, it doesn't crash anymore. So there is something wrong with LeptonicaFrameConverter?

@saudet
Copy link
Member

saudet commented Nov 24, 2018 via email

@saudet
Copy link
Member

saudet commented Nov 24, 2018 via email

@thach12345
Copy link

Any image.

@saudet
Copy link
Member

saudet commented Nov 24, 2018 via email

@saudet saudet added the bug label Nov 24, 2018
@saudet saudet reopened this Nov 24, 2018
@saudet
Copy link
Member

saudet commented Nov 24, 2018

It's possible for the JVM to deallocate LeptonicaFrameConverter and it's buffers after convert(), but before pixSauvolaBinarize() returns. Could you put those objects, for example, in thread-local storage and see what happens?

@thachvupham
Copy link
Author

Interesting and perhaps you are right. After adding an extra convert() it doesn't crash anymore:

private static BufferedImage binarize(ImageWritable image, float factor) {
        LeptonicaFrameConverter leptonicaFrameConverter = new LeptonicaFrameConverter();

        PIX pix = leptonicaFrameConverter.convert(image.getFrame().clone());
        PIX binarizedPix = new PIX(null);
        pixSauvolaBinarize(pix, 14, factor, 1, null, null, null, binarizedPix);

        BufferedImage result = fromBinarizedPix(binarizedPix);

        pixDestroy(binarizedPix);
        Frame frame = null;
        leptonicaFrameConverter.convert(frame);
        return result;
    }

saudet added a commit to bytedeco/javacpp-presets that referenced this issue Nov 25, 2018
@saudet
Copy link
Member

saudet commented Nov 26, 2018

Thanks for testing! I've fixed this in the commits above. It should work as expected now.

@saudet
Copy link
Member

saudet commented Jan 13, 2019

The fix has been released with JavaCPP and JavaCV 1.4.4. Thanks for reporting and for testing!

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

No branches or pull requests

3 participants