代码之家  ›  专栏  ›  技术社区  ›  Jorge Alvarado

Android java。lang.OutOfMemoryError仅适用于三星设备

  •  2
  • Jorge Alvarado  · 技术社区  · 7 年前

    异常跟踪如下:

    Fatal Exception: java.lang.RuntimeException: An error occured while executing doInBackground()
           at android.os.AsyncTask$3.done(AsyncTask.java:300)
           at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
           at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
           at java.util.concurrent.FutureTask.run(FutureTask.java:242)
           at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
           at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
           at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
           at java.lang.Thread.run(Thread.java:841)
    Caused by java.lang.OutOfMemoryError
           at java.util.Arrays.copyOfRange(Arrays.java:2684)
           at com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:467)
           at javax.crypto.Cipher.doFinal(Cipher.java:1204)
           at com.ijsoft.cpul.Util.DbMainFunctions.com.ijsoft.cpul.Util.AES256Cipher.decrypt(DbMainFunctions.java:2059)
           at com.ijsoft.cpul.Util.DbMainFunctions.initializeDb(DbMainFunctions.java:94)
           at com.ijsoft.cpul.SplashActivity$InitializeDb.doInBackground$9ecd34e(SplashActivity.java:2095)
           at android.os.AsyncTask$2.call(AsyncTask.java:288)
           at java.util.concurrent.FutureTask.run(FutureTask.java:237)
           at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
           at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
           at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
           at java.lang.Thread.run(Thread.java:841)
    

    在其他情况下,我收到以下跟踪:

    Fatal Exception: java.lang.RuntimeException: An error occured while executing doInBackground()
           at android.os.AsyncTask$3.done(AsyncTask.java:299)
           at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
           at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
           at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
           at java.util.concurrent.FutureTask.run(FutureTask.java:137)
           at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
           at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
           at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
           at java.lang.Thread.run(Thread.java:856)
    Caused by java.lang.OutOfMemoryError
           at java.io.ByteArrayOutputStream.expand(ByteArrayOutputStream.java:91)
           at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:201)
           at com.ijsoft.cpul.Util.DbMainFunctions.initializeDb(DbMainFunctions.java:90)
           at com.ijsoft.cpul.SplashActivity$InitializeDb.doInBackground$9ecd34e(SplashActivity.java:2095)
           at android.os.AsyncTask$2.call(AsyncTask.java:287)
           at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
           at java.util.concurrent.FutureTask.run(FutureTask.java:137)
           at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
           at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
           at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
           at java.lang.Thread.run(Thread.java:856)
    

    public class AES256Cipher {
        public byte[] decrypt(byte[] textBytes, Context context)
                throws java.io.UnsupportedEncodingException,
                NoSuchAlgorithmException,
                NoSuchPaddingException,
                InvalidKeyException,
                InvalidAlgorithmParameterException,
                IllegalBlockSizeException,
                BadPaddingException {
    
            byte[] keyBytes = CommonFunctions.md5Package(context).getBytes();
            byte[] ivBytes = new byte[16];
            for (int j = 0; j < keyBytes.length; j+=2) {
                ivBytes[j/2]=keyBytes[31-j];
            }
    
            AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
            SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
            return cipher.doFinal(textBytes);
        }
    }
    

    public synchronized static int initializeDb(int release, Context context) {
            int resultCode = 0;
            try {
                // Get the encrypted json file (database) from Assets
                AssetManager am = context.getAssets();
                InputStream is = am.open("assets");
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] buff = new byte[4096];
                int i;
                while ((i = is.read(buff, 0, buff.length)) > 0) {
                    baos.write(buff, 0, i);
                }
                is.close();
                baos.close();
                resultCode = updateDb(baos.toByteArray(), release, context);
                //baos.close();
            } catch (Exception e) {
                Log.e("DbMainFunctions", e.getMessage());
                //e.printStackTrace();
                resultCode = -1;
            }
            return resultCode;
        }
    
    public synchronized static int updateDb(byte[] cipherJson, int release, Context context) {
            int resultCode = 0;
            AES256Cipher aes256;
            try {
                aes256 = new AES256Cipher();
                cipherJson = aes256.decrypt(cipherJson, context);
            } catch (UnsupportedEncodingException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException |
                    InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
                Log.e("DbMainFuctions", e.getMessage());
                return -2;
            }
    
         ...
    }
    

    我的应用程序在这一点上做的是从APK中包含的assets目录中获取一个带有AES256的加密文件(文件名:assets)。然后解密文件并将其保存在字节数组中。文件大小约为4.4 MB。initializeDb()方法在doInBackground()期间从AsyncTask调用,也就是说,前面的所有代码都在AsyncTask中执行

    1 回复  |  直到 7 年前
        1
  •  4
  •   CommonsWare    7 年前

    这很可能给你一个 OutOfMemoryError

    至少,停止尝试将整个内容读入内存,并以流式方式解密数据(例如,每次16KB),将解密后的数据流式传输到输出文件(因为很可能您没有足够的内存来保存)。