把java对象传给jni层引起的异常分析

2017-04-08  本文已影响0人  uriah

问题描述:android项目中有一个native方法,比如

 static native boolean jniGetInfo(int var1,Integer var2); 

var2参数是作为出参来使用,c++层代码会修改此参数。
我之前的调用方式是:

 Integer var2 = 0;
 boolean ret = jniGetInfo(1,var2);

通过此调用方式,var2的值在C++层被修改。符合我想要的答案。但这样写之后,发现Gson解析json
字符串的时候,出现问题。屏蔽上面两行代码,则问题不会出现。
问题分析:为了解决此问题,我们首先要理解自动装箱的本质。当我们给一个Integer对象赋一个int值的时候,
会调用Integer类的静态方法valueOf,我们看一看valueOf方法就知道为什么会有这样的结果了
/**
* Returns a <tt>Integer</tt> instance representing the specified
* <tt>int</tt> value.
* If a new <tt>Integer</tt> instance is not required, this method
* should generally be used in preference to the constructor
* {@link #Integer(int)}, as this method is likely to yield
* significantly better space and time performance by caching
* frequently requested values.
*
* @param i an <code>int</code> value.
* @return a <tt>Integer</tt> instance representing <tt>i</tt>.
* @since 1.5
*/
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}

通过上面的代码可以发现,其实当valueOf()入参是>=-128,<=IntergerCache.high时,没有创建新的Interger对象,
而是使用IntegetCache.cache[]数组中缓存的对象。

     private static class IntegerCache {  

    static final int high;  
    static final Integer cache[]; 

    static {  

        final int low = -128;  
        int h = 127;  

        if (integerCacheHighPropValue != null) {  

            int i = Long.decode(integerCacheHighPropValue).intValue();  
            i = Math.max(i, 127);  
            h = Math.min(i, Integer.MAX_VALUE - -low);  
        }  
        high = h;  

        cache = new Integer[(high - low) + 1];  
        int j = low;  
        for(int k = 0; k < cache.length; k++)  
            cache[k] = new Integer(j++);  
    }  

    private IntegerCache() {}  
}  

Integer里面有一个内部类IntegerCache,是用来做缓存优化性能的,默认缓存了-128到127中间的数字,
如果是-128到127之间的就直接使用缓存。
我们发现,IntergerCache是private,只有Interger类才能访问此内部对象。也就是说通过java语法,是无法
修改IntegerCache对象的。
但由于我们把IntegerCache中内存直接转给C++,这样跨语言访问,则C++层就可以越过这些限制,修改
缓存数组中的值,出现异常。

无标题.png

结论:当我们使用NDK开发android程序时,当C++层需要修改上层对象时,尽量保证我们传给C++的对象,是
我们new的,而尽量避免把通过调用其他方法返回的对象传给C++层。
所以上面代码改为:

  Integer var2 = new Integer(0);
  boolean ret = jniGetInfo(1,var2);

问题修复。

上一篇下一篇

猜你喜欢

热点阅读