import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.RandomAccessFile; import java.nio.CharBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import javax.swing.JTextArea; public class Test { public static void main(String[] args) throws InterruptedException { long startFreeMemory = Runtime.getRuntime().freeMemory(); System.out.println("start free memory is: " + startFreeMemory); try { new Test().go2(); long endFreeMemory = Runtime.getRuntime().freeMemory(); System.out.println("end free memory is: " + endFreeMemory); } catch (Exception e) { long endFreeMemory = Runtime.getRuntime().freeMemory(); System.out.println("end free memory is: " + endFreeMemory); e.printStackTrace(); } } public void go1() throws Exception { FileChannel fChannel = new RandomAccessFile("temp", "r").getChannel(); MappedByteBuffer mByteBuffer = fChannel.map(FileChannel.MapMode.READ_ONLY, 0, fChannel.size()); Charset charset = Charset.forName("iso-8859-1"); CharsetDecoder decoder = charset.newDecoder(); CharBuffer charBuffer = CharBuffer.allocate(1024); charBuffer = decoder.decode(mByteBuffer); JTextArea jta = new JTextArea(); System.out.println("set text length = " + new String(charBuffer.array(), 0, charBuffer.limit()).length()); jta.setText(new String(charBuffer.array(), 0, charBuffer.limit())); fChannel.close(); } public void go2() throws Exception { String text = ""; BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("temp"))); String line = null; JTextArea jta = new JTextArea(); while ((line = br.readLine()) != null) { text += line; text += "\n"; jta.setText(text); // jta.append(line); //使用此处屏蔽的两行就会内存溢出 // jta.append("\n"); System.out.println(line); } br.close(); } }
使用此处屏蔽的两行替换setText方式就会溢出,原因在于JTextArea的append方法有更严格的限制:
最终会进入javax.swing.text.BoxView类的如下方法:
/** * Resizes the given layout array to match the new number of * child views. The current number of child views are used to * produce the new array. The contents of the old array are * inserted into the new array at the appropriate places so that * the old layout information is transferred to the new array. * * @param oldArray the original layout array * @param offset location where new views will be inserted * @param nInserted the number of child views being inserted; * therefore the number of blank spaces to leave in the * new array at location <code>offset</code> * @return the new layout array */ int[] updateLayoutArray(int[] oldArray, int offset, int nInserted) { int n = getViewCount(); int[] newArray = new int[n]; System.arraycopy(oldArray, 0, newArray, 0, offset); System.arraycopy(oldArray, offset, newArray, offset + nInserted, n - nInserted - offset); return newArray; }
错误堆栈:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at javax.swing.text.BoxView.updateLayoutArray(BoxView.java:194)
at javax.swing.text.BoxView.replace(BoxView.java:168)
at javax.swing.text.View.updateChildren(View.java:1095)
at javax.swing.text.View.insertUpdate(View.java:679)
at javax.swing.plaf.basic.BasicTextUI$RootView.insertUpdate(BasicTextUI.java:1589)
at javax.swing.plaf.basic.BasicTextUI$UpdateHandler.insertUpdate(BasicTextUI.java:1848)
at javax.swing.text.AbstractDocument.fireInsertUpdate(AbstractDocument.java:185)
at javax.swing.text.AbstractDocument.handleInsertString(AbstractDocument.java:734)
at javax.swing.text.AbstractDocument.insertString(AbstractDocument.java:693)
at javax.swing.text.PlainDocument.insertString(PlainDocument.java:114)
at javax.swing.JTextArea.append(JTextArea.java:470)
at Test.go2(Test.java:48)
at Test.main(Test.java:18)
同样的文件,BufferedReader为什么会失败呢?