JNA中内存处理-Structure

本文探讨了Java Native Access (JNA) 中结构体的内存管理机制,包括结构体的分配、同步及垃圾回收等关键过程。通过四个具体测试案例,深入分析了不同情况下结构体在Java堆和本地堆中的行为差异。
摘要由CSDN通过智能技术生成

API描述:

Structures are normally written to native memory before and read back from native memory after a function call. With very large structures, there can be a performance hit using reflection to walk through all the fields. Structure auto-synch can be disabled by calling Structure.setAutoSynch(boolean) with a false parameter. It is then up to you to use Structure.readField(String) andStructure.writeField(String) or Structure.writeField(String,Object) to synch with just the fields of interest.


测试工具:

1. Top

2. Jconsole


测试用例1:

C Code:

struct _Company1
{
    int history;
    int employeeId[20000000];
};
typedef struct _Company1 Company1;

void checkCompany1(Company1 *company)
{
    printf("Into C_Employee ID: %d\n", company->employeeId[0]);
    fflush(stdout);
    company->employeeId[0] = 1;
    sleep(5);
}


Java Code:

public class Company1 extends Structure{
public int history;
public int []employeeId = new int[20000000];
}


public static void testStructure1()
{
sleep(60);
while(true)
{
Company1 company = new Company1();
company.employeeId[0] = 0;
libben.checkCompany1(company);
System.out.format("Into Java_Employee ID: %d", company.employeeId[0]);
System.out.println();
}
}


现象:

1. 当每次创建一个Company1的时候,Java的Old Heap会分配80M内存;

2. 当每次创建一个Company1的时候,虚拟内存会分配80M;驻留内存会增加160M内存,其中80M是Java的Old Heap中,还有80M是 Native Heap中的;之所以虚拟内存不会增加160M,是因为Java的Old Heap是之前分配的虚拟内存的一部分。

3. 如果在jconsole中不手工执行一次GC,会出现OutOfMemoryException,这可能是JVM的优化,认为从来没有执行过GC而Old Heap已满是问题;

4. 如果手工执行过一次GC,不会出现OutOfMemoryException,当JVM Old Heap满的时候会执行完全GC,这个时候驻留内存释放的内存远远大于Java Old Heap释放的内存。


结论:

1. 创建Structure的时候,当然是创建在Java Heap中;

2. 在执行JNA call之前,会在Native Heap中分配同样大小内存,并且将Structure中内存从Java Heap中拷贝到C Native Heap中;

3. 根据执行结果可以发现,在执行JNA call结束以后,执行结果会从Native Heap Memory拷贝回Java Heap中;

4. 如果GC的时候,Java Heap和C Heap中的内容都要回收,不会出现C Heap中的内存泄露


测试用例2:

C code:

struct _President
{
    int student[10000000];
};
typedef struct _President President;


struct _Company2
{
    int history;
    int employeeId[20000000];
    President *presidents[1];
};


typedef struct _Company2 Company2;


void checkCompany2(Company2 *company)
{
    printf("Into C_Student ID: %d\n", company->presidents[0]->student[0]);
    fflush(stdout);
    company->presidents[0]->student[0]= 1;
    sleep(5);
}

Java Code:

public class President  extends Structure{
public static class ByReference extends President implements Structure.ByReference { }
public static class ByValue extends President implements Structure.ByValue { }
public int []student = new int[10000000];
}

public class Company2 extends Structure{
public int history;
public int []employeeId = new int[20000000];
public President.ByReference []presidents = new President.ByReference[1];
}


public static void testStructure2()
{
sleep(1);
while(true)
{
President.ByReference president = new President.ByReference();

Company2 company = new Company2();
company.presidents[0] = president;

company.presidents[0].student[0] = 0;
libben.checkCompany2(company);
System.out.format("Into Java_Student ID: %d", company.presidents[0].student[0]);
System.out.println();
}
}


现象:

1.Java的Eden Heap增加了40M空间,为President对象的;Java的Old Heap增加了80M空间,为Company对象的;

2.驻留内存增加了240M空间,虚拟内存增加了120M空间;


结论:

1.直接传给JNA call的Structure会被放到Old Heap,很奇怪为什么要这么处理;

2.非直接传给JNA call的Structure会被放到Eden Heap.

3.指针数组所对应的内容也能被自动拷贝到Native空间,这个和良少如下这篇文章不吻合,可能是新的JNA做了修改

http://blog.csdn.net/shendl/article/details/3599849


测试用例3:

public static void testStructure3()
{
sleep(1);
while(true)
{
President.ByReference president = new President.ByReference();

Company2 company = new Company2();
company.setAutoSynch(false);
company.presidents[0] = president;

company.presidents[0].student[0] = 0;
libben.checkCompany2(company);
System.out.format("Into Java_Student ID: %d", company.presidents[0].student[0]);
System.out.println();
}
}


现象:

1. 运行结果是如下如下core

#  SIGSEGV (0xb) at pc=0x00002aaabec3b882, pid=30130, tid=1078044992
#
# JRE version: 7.0_05-b06
# Java VM: Java HotSpot(TM) 64-Bit Server VM (23.1-b03 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libben.so+0x882]  checkCompany2+0x17


结论:

1. 调用了company.setAutoSynch(false)以后,在调用JNA core之前,president没有被拷贝到Native Heap中,导致访问出错。


测试用例4:

C Code:

void checkCompany2(Company2 *company)
{
    //printf("Into C_Student ID: %d\n", company->presidents[0]->student[0]);
    //fflush(stdout);
    //company->presidents[0]->student[0]= 1;
    sleep(60);
}

Java Code:

public static void testStructure3()
{
sleep(60);
while(true)
{
President.ByReference president = new President.ByReference();

Company2 company = new Company2();
company.setAutoSynch(false);
company.presidents[0] = president;

company.presidents[0].student[0] = 0;
libben.checkCompany2(company);
System.out.format("Into Java_Student ID: %d", company.presidents[0].student[0]);
System.out.println();
}
}

现象:

1. Java的Eden Heap增加了40M内存;Java 的Old Heap增加了80M内存;

2. 虚拟内存增加了80M内存;驻留内存增加了200M内存;


结论:

1.作为JNA call的Structure分配了80M内存在Java Old Heap中;

2.作为非JNA call的Structure分配了40M内在在Java Eden Heap中;

3.非JNA call的Structure没有被拷贝到Native Heap Memory中;

4.如果C的函数中不需要使用President,整个程序可以正常运行。


根据以上用例再回头读读API中的内容就清晰了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值