發現Java虛擬機內存泄露問題
原創常規理解上,Java的內存管理機制是將局部變量保存在堆中,當變量的作用域結束之后,該變量所占用的內容會被自動回收。不需要做任何特殊的處理。比如下面的代碼:
- public class JavaMemory{
- private final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6);
- public void f(){
- {
- byte[] data1 = new byte[dataSize];
- }
- byte[] data2 = new byte[dataSize];
- }
- public static void main(String[] args) {
- JavaMemoryPuzzle jmp = new JavaMemoryPuzzle();
- jmp.f();
- }
- }
在這個例子中,方法f()里定義了兩個局部變量,變量data1和data2的作用域不同。按照正常理解,雖然兩各個數組所需要的內存之和已經超過了可用內存,但是因為data1會被及時回收,不會出現內存溢出錯誤。
如果我們實際執行這個例子,會發現出現了java.lang.OutOfMemoryError錯誤。這是為什么?如果在BEA或者IBM的虛擬機上測試過這個例子,并不會出現錯誤。也就是說,SUN的JVM在內存回收機制上存在漏洞或者BUG。
這個問題該如何修正呢,方法其實很簡單。只需要在變量作用域結束之前,將變量置為空就可以了。修改之后的結果如下:
- public class JavaMemory{
- private final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6);
- public void f(){
- {
- byte[] data1 = new byte[dataSize];
- data1 = null;
- }
- byte[] data2 = new byte[dataSize];
- }
- public static void main(String[] args) {
- JavaMemoryPuzzle jmp = new JavaMemoryPuzzle();
- jmp.f();
- }
- }
發現這個問題,對于Java開發者來說也許會很緊張,擔心自己的代碼是否會出現同樣問題。大家盡可放心,連續出現兩個變量占用內存之和超過內存限制的情況概率非常小。并且在兩個變量之間,如果定義了其他變量也不會出現這個問題。如下面的代碼就不會出現問題:
- public class JavaMemory{
- private final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6);
- public void f(){
- {
- byte[] data1 = new byte[dataSize];
- }
- int i=1;
- byte[] data2 = new byte[dataSize];
- }
- public static void main(String[] args) {
- JavaMemoryPuzzle jmp = new JavaMemoryPuzzle();
- jmp.f();
- }
- }
【編輯推薦】