uima-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Benjamin De Boe (JIRA)" <...@uima.apache.org>
Subject [jira] [Commented] (UIMA-4899) UIMACPP access violation when running in multiple threads
Date Mon, 25 Apr 2016 12:27:12 GMT

    [ https://issues.apache.org/jira/browse/UIMA-4899?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15256278#comment-15256278
] 

Benjamin De Boe commented on UIMA-4899:
---------------------------------------

After some more debugging, it seems this is probably a garbage collection issue rather than
a multi-threading issue, although multiple threads may well increase the likelihood of it
happening.

We've found that there are two methods on the CPP side for cleaning up the memory used by
the CPP engine: destroyJNI() and destructorJNI(). destructorJNI() is called from the UimacppEngine:finalize()
method and only deletes the pInstance pointer, whereas destroyJNI() does a lot more work in
cleaning up what lies beyond and is called through UimacppEngine:destroy(), which in turn
is invoked from UimacppAnalysisComponent:finalize().

Now, the arcane magic in the GC process seems to first finish off the UimacppEngine helper
object (calling destructorJNI()) and then the UimacppAnalysisComponent instance that contained
the other one, with its destroyJNI() method then running into trouble because pInstance was
already deleted in destructorJNI(), causing the access violation we've been struggling with.


> UIMACPP access violation when running in multiple threads
> ---------------------------------------------------------
>
>                 Key: UIMA-4899
>                 URL: https://issues.apache.org/jira/browse/UIMA-4899
>             Project: UIMA
>          Issue Type: Bug
>          Components: C++ Framework
>    Affects Versions: 2.8.1SDK
>         Environment: Windows 10 64bit
>            Reporter: Benjamin De Boe
>
> When running a bunch of threads accessing separate AE instances of the UIMACPP DaveDetector
in JNI mode, the process crashes with an access violation on the call to "delete pInstance"
in destructorJNI in jni/jni.cpp.
> The code below should allow you to reproduce the issue and takes three command-line arguments:
> 1: the full path to DaveDescriptor.xml
> 2: whether to use simple threads ("n") or separate processes ("y")
> 3: (optional, default 20) size of the CAS pool to use, which we found out has an impact
in reproducing the issue.
> /*
>  * To change this license header, choose License Headers in Project Properties.
>  * To change this template file, choose Tools | Templates
>  * and open the template in the editor.
>  */
> package com.intersys.uima.test;
> import java.io.File;
> import java.net.URL;
> import java.net.URLClassLoader;
> import org.apache.uima.UIMAFramework;
> import org.apache.uima.analysis_engine.AnalysisEngine;
> import org.apache.uima.cas.CAS;
> import org.apache.uima.resource.ResourceSpecifier;
> import org.apache.uima.util.CasCreationUtils;
> import org.apache.uima.util.CasPool;
> import org.apache.uima.util.Level;
> import org.apache.uima.util.XMLInputSource;
> /**
>  *
>  * @author bdeboe
>  */
> public class Standalone implements Runnable {
>     private String text;
>     private AnalysisEngine ae;
>     private CasPool pool;
>     public Standalone(String txt, AnalysisEngine ae, CasPool pool) {
>         this.text = txt;
>         this.ae = ae;
>         this.pool = pool;
>     }
>     public static void main(String[] args) throws Exception {
>         String descPath = ((args != null) && (args.length > 0)) ? args[0]
: "C:\\InterSystems\\UIMA\\bin\\DaveDetector.xml";
>  
>         if ((args != null) && (args.length > 1) && (args[1].charAt(0)
== 'y')) {
>             async(descPath);
>             return;
>         }
>         
>        int casPoolSize = ((args != null) && (args.length > 2)) ? Integer.valueOf(args[2])
: 20;
>         XMLInputSource in = new XMLInputSource(descPath);
>         ResourceSpecifier specifier
>                 = UIMAFramework.getXMLParser().parseResourceSpecifier(in);
>         AnalysisEngine ae = UIMAFramework.produceAnalysisEngine(specifier);
>         CasPool pool = (casPoolSize > 0) ? new CasPool(casPoolSize, ae) : null;
>         String loremIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
anim id est laborum.";
>         for (int i = 0; i < 25; i++) {
>             Standalone task = new Standalone(loremIpsum, UIMAFramework.produceAnalysisEngine(specifier),
(casPoolSize > 0) ? pool : null);
>             Thread t = new Thread(task);
>             t.start();
>         }
>     }
>     public static int async(String descriptor) throws Exception {
>         String javaHome = System.getProperty("java.home");
>         String javaBin = javaHome
>                 + File.separator + "bin"
>                 + File.separator + "java";
>         //String classpath = System.getProperty("java.class.path");
>         URL[] urls = ((URLClassLoader) Thread.currentThread().getContextClassLoader()).getURLs();
>         StringBuilder classPath = new StringBuilder();
>         for (URL url : urls) {
>             classPath.append(url.getPath()).append(";");
>         }
>         System.out.println(javaBin.concat(" -cp ").concat(classPath.toString()).concat("
").concat(Standalone.class.getCanonicalName()).concat(" ").concat(descriptor));
>         ProcessBuilder builder = new ProcessBuilder(
>                 javaBin, "-cp", classPath.toString(), Standalone.class.getCanonicalName(),
descriptor);
>         builder.redirectErrorStream(true);
>         builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
>         Process[] processes = new Process[4];
>         processes[0] = builder.start();
>         processes[1] = builder.start();
>         processes[2] = builder.start();
>         processes[3] = builder.start();
>         int done = 0;
>         do {
>             Thread.sleep(1000);
>             done = 0;
>             for (int i = 0; i < 4; i++) {
>                 if (!processes[i].isAlive()) {
>                     done++;
>                 }
>             }
>             System.out.println(String.valueOf(done).concat(" processes done"));
>         } while (done < 4);
>         return processes[3].exitValue();
>     }
>     @Override
>     public void run() {
>         CAS cas  = null;
>         try {
>             if (pool != null) { 
>                 cas = pool.getCas();
>             } else {
>                 cas = CasCreationUtils.createCas(ae.getAnalysisEngineMetaData());
>             }
>             UIMAFramework.getLogger().log(Level.WARNING, "created CAS in thread ".concat(String.valueOf(Thread.currentThread().getId())));
>             cas.setDocumentText(text);
>             ae.process(cas);
>             
>             System.out.println("Done processing text");
>         } catch (Exception e) {
>             e.printStackTrace();
>         } finally {
>             if (pool != null) pool.releaseCas(cas);
>         }
>     }
> }



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Mime
View raw message