Java应用程序通过JNI调用C ++ DLL;如何最好地分配内存? [英] Java app calls C++ DLL via JNI; how best to allocate memory?

查看:341
本文介绍了Java应用程序通过JNI调用C ++ DLL;如何最好地分配内存?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题的基本概要是:
如何最佳地优化我的内存分配,以尽可能多的内存给我通过JNI访问的DLL?我应该以什么为目标来最小化,我应该如何最大化等等。



SYSTEM:
运行JBoss 6作为32位的Windows 32服务系统具有4 GB RAM。我明白,Java堆的内存最大限制。 JVM是 JRE1.6.0_26



SERVICE:
JBoss下安装的是一个webapp,它接收客户端的请求;每个请求通过JNI调用C ++构建的DLL,以某种方式处理图像文件。



ISSUE:
有时,使用较大或一些(不是全部)LZW压缩映像,调用的java类接收到一个消息,该DLL经历了一个全局内存耗尽,无法完成请求的过程。



除了基本的Windows进程之外,服务器上还没有任何其他内容可以正常运行。



目前的JBOSS App Server内存设置如下,但可能会过多:



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



我正在尝试确定最佳内存设置,为JNI DLL提供尽可能多的资源,因为我明白JNI不使用分配给Java堆的任何内存。



我已经阅读了这些,但没有找到有用的回答我的问题:



Java JNI:内存分配/分区



可以使用jconsole来识别JNI C ++对象中的内存泄漏吗?



目前提供的两个答案没有解决无关问题。



当前内存JBoss服务器一周之后,JVM参数设置如上(TaskManager表示java.exe进程为750,672k)

 总内存池:5 

池:代码缓存(非堆内存)

峰值用法:init:2359296,已使用:7317312,承诺:7438336,最大:50331648
当前用法:init:2359296,used:7306496,committed:7438336,max:50331648


| --------- |承诺:7.09Mb
+ ----------------------------------------- ---------------------------- +
| ///////// |最大:48Mb
+ ------------------------------------------ --------------------------- +
| --------- |使用:6.97Mb


池:PS Eden空间(堆内存)

峰值用法:init:268500992,used:354811904,committed:354811904,max: 355991552
当前用法:init:268500992,used:270153472,committed:354091008,max:354156544


| -------------- -------------------------------------------------- ---- |承诺:337.69Mb
+ ----------------------------------------- ---------------------------- +
| //////////////// ///////////////////////////////////最大:337.75Mb
+ ----------------------------------------- ---------------------------- +
| ---------------- ------------------------------------ |使用:257.64Mb


池:PS幸存者空间(堆内存)

峰值用法:init:44695552,使用:44694896,提交:78643200,max: 78643200
当前用法:init:44695552,used:0,committed:1835008,max:1835008


| -------------- -------------------------------------------------- ----- |承诺:1.75Mb
+ ----------------------------------------- ---------------------------- +
| |最大:1.75Mb
+ ----------------------------------------- ---------------------------- +
|使用:0b


池:PS旧版(堆内存)

峰值用法:init:715849728,已用:123671968,提交:715849728,最多:715849728
当前用法:init:715849728,used:104048648,committed:715849728,max:715849728


| --------------- -------------------------------------------------- ---- |承诺:682.69Mb
+ ----------------------------------------- ---------------------------- +
| ////////// |最大:682.69Mb
+ ----------------------------------------- ---------------------------- +
| --------- |使用:99.23Mb


池:PS Perm Gen(非堆内存)

峰值用法:init:16777216,已用:91989664,提交:134217728, max:134217728
当前用法:init:16777216,used:90956472,committed:90963968,max:134217728


| ------------ ---------------------------------- |承诺:86.75Mb
+ ----------------------------------------- ---------------------------- +
| //////////////// ////////////////////////////// | |最大:128Mb
+ ------------------------------------------ --------------------------- +
| ----------------- ----------------------------- |使用:86.74Mb


解决方案

由JNI分配给JVM进程,但不受您的Java代码的控制。它不是堆的一部分,并且不能通过JVM参数进行调整。基本上,使用本机malloc分配的任何东西都必须由本机代码进行管理。如果您控制着您正在使用的库,那么您必须通过它来检查资源泄漏。这是非常重要的,如果这是一个长寿的过程中使用。



根据我的经验,最好的方法是检查你的实际内存使用拉拉的JMX统计暴露由JVM。一旦了解了Java应用程序消耗的内存量,您将会更好地了解如何设置最大堆设置。 Permgen空间用于类定义,所以你真的不应该需要很多内存,除非你正在做一堆动态类加载。



虽然你不能调整可用于JNI库的内存,调整为您的堆保留的内存,这样可能会释放资源供库使用。



正如预期的那样,添加堆内存峰值一起出现到大约1022.19(你的堆的最大大小)。当堆耗尽时,完整的GC运行被启动,脏堆被回收。根据您提供的数字,我建议从Xmx512m开始。这将使您的JNI代码空间呼吸。



如果发现由于垃圾回收过多而导致JVM崩溃,这意味着您的Java堆用尽,您可以增加该分配。然而,如果它快速地吃掉了512mb,造成了明显的性能影响,那么不大可能,任何不大的增长都将产生很大的影响。这一切都在很大程度上取决于你的程序,它吃多快的Java堆,以及全部GC运行的有效性。


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

解决方案

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.

这篇关于Java应用程序通过JNI调用C ++ DLL;如何最好地分配内存?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆