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中的内容就清晰了