Java app calls C++ DLL via JNI; how best to allocate memory?

12,458

Memory allocated by the native code wrapped by JNI is allocated to the JVM process, but is not under the control of your Java code. It is not part of the heap, and is not tunable via JVM parameters. Basically, anything allocated with a native malloc must be managed by that native code. If you are in control of the libraries you are using, its imperative that you go through it and check for resource leaks. This is especially important if this is being used in a long lived process.

In my experience the best approach would be to examine your actual memory use by pulling the JMX stats exposed by the JVM. Once you have an idea about how much memory your Java app consumes You'll have a better idea about where to set your max heap settings. Permgen space is used for class definitions and such, so you really shouldn't need much memory there unless you are doing a bunch of dynamic class loading.

While you cannot tune the memory available for the JNI library, tuning the memory reserved for your heap and such will potentially free up resources for use by the library.

As would be expected, adding the heap memory peaks together it comes out to about 1022.19 (the max size of your heap). When the heap is exhausted a full GC run is kicked off and dirty heap is reclaimed. Based on the numbers that you have provided, I'd suggest starting with a Xmx512m. This will give your JNI code room to breath.

If you find that the JVM is thrashing due to excessive garbage collection, meaning that you're running out of Java heap too quickly, you could grow that allocation. However, if it is eating up 512mb rapidly enough to cause a noticeable performance impact, its unlikely that anything short of a significant increase will have much effect. This all depends heavily on your program, how quickly it eats the Java heap, and how effective the full GC run is.

Share:
12,458
JoshDM
Author by

JoshDM

I have the appropriate technical skills for answering the questions that I answer. My avatar was created using Mad Men Yourself.

Updated on June 23, 2022

Comments

  • JoshDM
    JoshDM almost 2 years

    Basic summary of question is: How do I best optimize my memory allocation to give as much memory to the DLLs I access through JNI as possible? What should I aim to minimize, what should I aim to maximize, etc.

    SYSTEM: Running JBoss 6 as a Windows 32 Service in a 32-bit system with 4 GB RAM. I do understand there are maximum restrictions on memory for Java Heap. JVM is JRE1.6.0_26

    SERVICE: Installed under JBoss is a webapp which receives requests from clients; each request calls the C++-built DLL through JNI to process an image file in some fashion or other.

    ISSUE: Occasionally, with larger or some (not all) LZW-compression images, the calling java class receives a message that the DLL experienced a Global Memory Depletion and failed to complete the requested process.

    There is nothing else actively running on the server beyond basic windows processes.

    Current JBOSS App Server memory settings are as follows, but may be excessive:

    -Xms1024m -Xmx1024m -Xss1024k -XX:MaxPermSize=128m

    I am trying to determine the best memory settings to give as much resources to the JNI DLL, as I understand JNI does not use any memory allocated to the Java Heap.

    I have read these, but did not find them helpful to answer my question:

    Java JNI : Memory allocation / partitioning

    Can jconsole be used to identify memory leaks in JNI C++ objects?

    The two answers currently supplied do not address the inherient question.

    Current memory of JBoss server after one week with JVM params set as above (TaskManager indicates java.exe process at 750,672k)

    Total Memory Pools: 5
    
    Pool: Code Cache (Non-heap memory)
    
        Peak Usage : init:2359296, used:7317312, committed:7438336, max:50331648
        Current Usage : init:2359296, used:7306496, committed:7438336, max:50331648
    
    
            |---------| committed:7.09Mb
            +---------------------------------------------------------------------+
            |/////////| | max:48Mb
            +---------------------------------------------------------------------+
            |---------| used:6.97Mb
    
    
    Pool: PS Eden Space (Heap memory)
    
        Peak Usage : init:268500992, used:354811904, committed:354811904, max:355991552
        Current Usage : init:268500992, used:270153472, committed:354091008, max:354156544
    
    
            |--------------------------------------------------------------------| committed:337.69Mb
            +---------------------------------------------------------------------+
            |///////////////////////////////////////////////////// || max:337.75Mb
            +---------------------------------------------------------------------+
            |----------------------------------------------------| used:257.64Mb
    
    
    Pool: PS Survivor Space (Heap memory)
    
        Peak Usage : init:44695552, used:44694896, committed:78643200, max:78643200
        Current Usage : init:44695552, used:0, committed:1835008, max:1835008
    
    
            |---------------------------------------------------------------------| committed:1.75Mb
            +---------------------------------------------------------------------+
            | | max:1.75Mb
            +---------------------------------------------------------------------+
            | used:0b
    
    
    Pool: PS Old Gen (Heap memory)
    
        Peak Usage : init:715849728, used:123671968, committed:715849728, max:715849728
        Current Usage : init:715849728, used:104048648, committed:715849728, max:715849728
    
    
            |---------------------------------------------------------------------| committed:682.69Mb
            +---------------------------------------------------------------------+
            |////////// | max:682.69Mb
            +---------------------------------------------------------------------+
            |---------| used:99.23Mb
    
    
    Pool: PS Perm Gen (Non-heap memory)
    
        Peak Usage : init:16777216, used:91989664, committed:134217728, max:134217728
        Current Usage : init:16777216, used:90956472, committed:90963968, max:134217728
    
    
            |----------------------------------------------| committed:86.75Mb
            +---------------------------------------------------------------------+
            |//////////////////////////////////////////////| | max:128Mb
            +---------------------------------------------------------------------+
            |----------------------------------------------| used:86.74Mb
    
  • allingeek
    allingeek over 12 years
    In case I haven't stated this specifically enough. You really have no way of setting a maximum limit on the amount of memory that your JNI library can request.
  • JoshDM
    JoshDM over 12 years
    So are you saying to minimize overall memory allocated to the JVM process? Should I be able to subtract the total memory value given by JMX from the value consumed by /allocated to the JVM process to determine the amount used by the DLL?
  • allingeek
    allingeek over 12 years
    Yes, approximately. The process heap (which contains the Java heap plus everything else) is restricted to approximately 2GB on a 32 bit architecture. The limit is much larger on a 64 bit arch. If you are allocating gigs of memory specifically to the Java heap and other Java specific components of your programs memory, that doesn't leave much room for the JNI memory allocation (which is allocated against the process heap).
  • allingeek
    allingeek over 12 years
    The "everything else" part of the process heap includes: Permenent Space, Code Generation, Socket Buffers, Thread Stacks, Direct Memory Space, JNI Code, Garbage Collection and JNI allocated memory. So while, a subtraction would give you the total of this space, its not only going to be the JNI allocated space (though that might be its biggest consumer).
  • JoshDM
    JoshDM over 12 years
    OK then, let's take what I have here: -Xms1024m -Xmx1024m -Xss1024k -XX:MaxPermSize=128m. Assuming I do not need these values to be as high as they are (I am restricted to 32-bit architecture), I should aim to lower the values of Xms, Xmx and MaxPermSize as much as possible to free up for JNI, correct? Do other runtime parameters exist that I might want to consider including, to possibly enhance the process heap allocation? JVM is JRE1.6.0_26
  • allingeek
    allingeek over 12 years
    Well, there are other parameters that will help you tune your Java heap usage, but these are the big ones. I'd exercise your code a bit to determine typical heap footprints and allocate that + 30-40% and set that as your max heap size. I'd leave Xms at defaults since you'd like to only use the memory you need, and unless you're seeing errors where you are specifically running out of Permgen space, I'd leave that alone as well. Unless you are running a massively multi-threaded application here, I'd leave Xss alone as well. The biggie here is Xmx (max heap size).