美文网首页
把java对象传给jni层引起的异常分析

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

作者: uriah | 来源:发表于2017-04-08 10:34 被阅读0次

    问题描述: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);
    

    问题修复。

    相关文章

      网友评论

          本文标题:把java对象传给jni层引起的异常分析

          本文链接:https://www.haomeiwen.com/subject/dmflattx.html