發(fā)現(xiàn)Java虛擬機(jī)內(nèi)存泄露問題
原創(chuàng)常規(guī)理解上,Java的內(nèi)存管理機(jī)制是將局部變量保存在堆中,當(dāng)變量的作用域結(jié)束之后,該變量所占用的內(nèi)容會(huì)被自動(dòng)回收。不需要做任何特殊的處理。比如下面的代碼:
- 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();
- }
- }
在這個(gè)例子中,方法f()里定義了兩個(gè)局部變量,變量data1和data2的作用域不同。按照正常理解,雖然兩各個(gè)數(shù)組所需要的內(nèi)存之和已經(jīng)超過了可用內(nèi)存,但是因?yàn)閐ata1會(huì)被及時(shí)回收,不會(huì)出現(xiàn)內(nèi)存溢出錯(cuò)誤。
如果我們實(shí)際執(zhí)行這個(gè)例子,會(huì)發(fā)現(xiàn)出現(xiàn)了java.lang.OutOfMemoryError錯(cuò)誤。這是為什么?如果在BEA或者IBM的虛擬機(jī)上測(cè)試過這個(gè)例子,并不會(huì)出現(xiàn)錯(cuò)誤。也就是說,SUN的JVM在內(nèi)存回收機(jī)制上存在漏洞或者BUG。
這個(gè)問題該如何修正呢,方法其實(shí)很簡單。只需要在變量作用域結(jié)束之前,將變量置為空就可以了。修改之后的結(jié)果如下:
- 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();
- }
- }
發(fā)現(xiàn)這個(gè)問題,對(duì)于Java開發(fā)者來說也許會(huì)很緊張,擔(dān)心自己的代碼是否會(huì)出現(xiàn)同樣問題。大家盡可放心,連續(xù)出現(xiàn)兩個(gè)變量占用內(nèi)存之和超過內(nèi)存限制的情況概率非常小。并且在兩個(gè)變量之間,如果定義了其他變量也不會(huì)出現(xiàn)這個(gè)問題。如下面的代碼就不會(huì)出現(xiàn)問題:
- 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();
- }
- }
【編輯推薦】