Android java.lang.OutOfMemoryError 仅限三星设备
Android java.lang.OutOfMemoryError only on Samsung devices
我在 Google Play 上有一个昨天更新的应用程序,我开始收到来自 Crashlytics 的大量报告,其中我的应用程序仅在 Android 4.x (4.1.1) 的三星设备上崩溃。 2 - 4.4.4).
异常轨迹如下:
Fatal Exception: java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask.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.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.doInBackgroundecd34e(SplashActivity.java:2095)
at android.os.AsyncTask.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor.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.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.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.doInBackgroundecd34e(SplashActivity.java:2095)
at android.os.AsyncTask.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.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)
发生错误的部分代码我留下:
AES256Cipher.java
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);
}
}
DbMainFunctions.java
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
中执行的
这很可能会给你一个 OutOfMemoryError
,特别是在 Android 5.0 之前,因为你不一定有 4.4MB 的连续空闲内存块。
我会取消加密,因为它不提供安全性(任何人都可以解密您的文件)并且会浪费 CPU、电池和内存。
至少,停止尝试将全部内容读入内存,并以流式方式解密数据(例如,一次 16KB),将解密后的数据流式传输到输出文件(因为您没有足够的数据)最有可能的记忆)。
我在 Google Play 上有一个昨天更新的应用程序,我开始收到来自 Crashlytics 的大量报告,其中我的应用程序仅在 Android 4.x (4.1.1) 的三星设备上崩溃。 2 - 4.4.4).
异常轨迹如下:
Fatal Exception: java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask.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.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.doInBackgroundecd34e(SplashActivity.java:2095)
at android.os.AsyncTask.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor.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.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.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.doInBackgroundecd34e(SplashActivity.java:2095)
at android.os.AsyncTask.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.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)
发生错误的部分代码我留下:
AES256Cipher.java
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);
}
}
DbMainFunctions.java
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
中执行的这很可能会给你一个 OutOfMemoryError
,特别是在 Android 5.0 之前,因为你不一定有 4.4MB 的连续空闲内存块。
我会取消加密,因为它不提供安全性(任何人都可以解密您的文件)并且会浪费 CPU、电池和内存。
至少,停止尝试将全部内容读入内存,并以流式方式解密数据(例如,一次 16KB),将解密后的数据流式传输到输出文件(因为您没有足够的数据)最有可能的记忆)。