我刚刚在一些旧手机上测试了我的设备,并收到了 java.lang.OutOfMemoryError。有人可以帮我解决这个问题吗?
我想做什么: 将一个非常大的字符串转换为html文件,该字符串由html文本组成。 这是我的代码:
OutputStream outputStream = null;
InputStream inputStream = null;
try {
inputStream = new ByteArrayInputStream(htmlContent.getBytes(Charset.forName("UTF-16")));
outputStream = new FileOutputStream(new File(dir, appBook.getPath()));
byte[] bufferData = new byte[512];
int bytesRead = inputStream.read(bufferData);
while (bytesRead != -1) {
outputStream.write(bufferData, 0, bytesRead); //add the bufferData data to the "new file"
bytesRead = inputStream.read(bufferData); // keep on reading and filling the dynamic byte araay until it returns -1
}
特别是 Charset.forName("UTF-16")) 导致这些旧设备上出现错误。如果我将 htmlContentString 缩短 2,则不会发生错误。
这让我觉得数组大小对于内存来说太大了?那么我应该如何处理这个问题呢?
日志猫
03-14 16:32:39.067 5604-5604/oskaro.synesthesia.oskar.leonad.synesthesiaconverter I/dalvikvm﹕ [ 03-14 16:32:39.067 5604: 5604 D/AndroidRuntime ]
Shutting down VM
03-14 16:32:39.067 5604-5604/oskaro.synesthesia.oskar.leonad.synesthesiaconverter W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x40fde2a0)
03-14 16:32:39.077 5604-5604/oskaro.synesthesia.oskar.leonad.synesthesiaconverter E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.OutOfMemoryError
at java.nio.charset.CharsetEncoderICU.getArray(CharsetEncoderICU.java:235)
at java.nio.charset.CharsetEncoderICU.encodeLoop(CharsetEncoderICU.java:169)
at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:415)
at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:283)
at java.nio.charset.Charset.encode(Charset.java:451)
at java.lang.String.getBytes(String.java:870)
at oskaro.synesthesia.oskar.leonad.synesthesiaconverter.HtmlAddDialog.createHtmlFile(HtmlAddDialog.java:120)
at oskaro.synesthesia.oskar.leonad.synesthesiaconverter.HtmlAddDialog.access$700(HtmlAddDialog.java:39)
at oskaro.synesthesia.oskar.leonad.synesthesiaconverter.HtmlAddDialog$4.onClick(HtmlAddDialog.java:209)
at android.view.View.performClick(View.java:4232)
at android.view.View$PerformClick.run(View.java:17298)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4921)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
at dalvik.system.NativeStart.main(Native Method)
最佳答案
当旧手机需要处理 getBytes 时,该字符串使用了太多内存。因此,我决定将字符串子串为 4 个字符串,而不只是将循环中的每个字符串写入输出流。
如果有人提供更好(更短、更干净或更快)的代码 fragment 来解决这个问题,我会将其标记为答案。直到那时,我的代码就可以了!
书写方法:
//divide the string by 4 and read it in chunks. Otherwise
// getBytes(Charset.forName("UTF-16") can cause out.of.memory if string is too big.
//Important, i have to call this outside the try{} otherwise it will only do 3 loops inside splitString()?????
String[] bookPieces = splitString(htmlContent, htmlContent.lenth()/650000);
OutputStream outputStream = null;
InputStream inputStream = null;
try {
outputStream = new FileOutputStream(new File(dir, appBook.getPath()));
for (String text : bookPieces) {
byte[] theBytes = text.getBytes(Charset.forName("UTF-16"));
inputStream = new ByteArrayInputStream(theBytes);
byte[] bufferData = new byte[1024];
int bytesRead = inputStream.read(bufferData);
while (bytesRead != -1) {
outputStream.write(bufferData, 0, bytesRead); //add the bufferData data to the "new file"
bytesRead = inputStream.read(bufferData); // keep on reading and filling the dynamic byte araay until it returns -1
}
//need to GC the inputsteam myself!!!!
inputStream = null;
}
辅助方法
private String[] splitString(String str, int elements) {
String[] splitStrings = new String[elements];
int currentLength = 0;
double oneFourth = str.length() / elements;
for (int x = 1; x <= splitStrings.length; x++) {
//for the last text chunk add "remainders" which were rounded down when (int)
if (x == splitStrings.length) {
splitStrings[x-1] = str.substring(currentLength, str.length());
} else {
splitStrings[x-1] = str.substring(currentLength, ((int) oneFourth)*x);
}
currentLength += (int) oneFourth;
}
return splitStrings;
}
关于java - 在 1024ram 及以下的设备上,将字符串转换为字节会导致 java.lang.OutOfMemoryError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29050758/