激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語(yǔ)言 - JAVA教程 - 理解Java垃圾回收

理解Java垃圾回收

2020-04-13 11:31趙杰A-124 JAVA教程

這篇文章主要幫助大家理解Java垃圾回收,通過(guò)實(shí)例學(xué)習(xí)java垃圾回收,什么是垃圾回收,感興趣的小伙伴們可以參考一下

當(dāng)程序創(chuàng)建對(duì)象、數(shù)組等引用類型的實(shí)體時(shí),系統(tǒng)會(huì)在堆內(nèi)存中為這一對(duì)象分配一塊內(nèi)存,對(duì)象就保存在這塊內(nèi)存中,當(dāng)這塊內(nèi)存不再被任何引用變量引用時(shí),這塊內(nèi)存就變成垃圾,等待垃圾回收機(jī)制進(jìn)行回收。垃圾回收機(jī)制具有三個(gè)特征:

垃圾回收機(jī)制只負(fù)責(zé)回收堆內(nèi)存中的對(duì)象,不會(huì)回收任何物理資源(例如數(shù)據(jù)庫(kù)連接,打開的文件資源等),也不會(huì)回收以某種創(chuàng)建對(duì)象的方式以外的方式為該對(duì)像分配的內(nèi)存,(例如對(duì)象調(diào)用本地方法中malloc的方式申請(qǐng)的內(nèi)存)
程序無(wú)法精確控制垃圾回收的運(yùn)行,只可以建議垃圾回收進(jìn)行,建議的方式有兩種System.gc() 和Runtime.getRuntime().gc()
在垃圾回收任何對(duì)象之前,總會(huì)先調(diào)用它的finalize()方法,但是同垃圾回收的時(shí)機(jī)一致,調(diào)用finalize()方法的時(shí)機(jī)也不確定。
針對(duì)以上三個(gè)特征,有三個(gè)問(wèn)題:

1、必須手動(dòng)的進(jìn)行清理工作,釋放除創(chuàng)建對(duì)象的方式以外的方式分配的內(nèi)存和其它的物理資源。并且要注意消除過(guò)期的對(duì)象引用,否則可能引起OOM。

手動(dòng)清理通常用到try...finally...這樣的代碼結(jié)構(gòu)。

示例如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
 
public class ManualClear {
 
 public static void main(String[] args) {
  FileInputStream fileInputStream = null;
  try {
   fileInputStream = new FileInputStream("./src/ManualClear.java");
  } catch (FileNotFoundException e) {
   System.out.println(e.getMessage());
   e.printStackTrace();
   return;
  }
 
  try {
   byte[] bbuf = new byte[1024];
   int hasRead = 0;
   try {
    while ((hasRead = fileInputStream.read(bbuf)) > 0) {
     System.out.println(new String(bbuf, 0, hasRead));
    }
   } catch (IOException e) {
    e.printStackTrace();
   }
  } finally {
   try {
    fileInputStream.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }
 
}

對(duì)于過(guò)期對(duì)象的引用,引起的OOM通常有三種常見的情況,這三種情況通常都不易發(fā)現(xiàn),短時(shí)間內(nèi)運(yùn)行也不會(huì)有什么問(wèn)題,但是時(shí)間久了后,泄漏的對(duì)象增加后終會(huì)引起程序崩潰。

類自己管理內(nèi)存時(shí),要警惕內(nèi)存泄漏
示例如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import java.util.Arrays;
import java.util.EmptyStackException;
 
class Stack{
 private Object[] elements;
 private int size;
 private static final int DEFAULT_INITAL_CAPACITY = 16;
 
 public Stack() {
  elements = new Object[DEFAULT_INITAL_CAPACITY];
 }
 
 public void push(Object e){
  ensureCapacity();
  elements[size++] = e;
 }
 
 public Object pop() {
  if (size == 0) {
   throw new EmptyStackException();
  }
  
  return elements[--size];
 }
 
 private void ensureCapacity() {
  if (elements.length == size) {
   elements = Arrays.copyOf(elements, 2 * size + 1);
  }
 }
}
 
public class StackDemo {
 
 public static void main(String[] args) {
  Stack stack = new Stack();
  
  for (int i = 0; i < 10000; i++) {
   stack.push(new Object());
  }
  
  for(int i = 0; i < 10000; i++) {
   stack.pop();
  }
 }
 
}

之所以會(huì)內(nèi)存泄漏,是因?yàn)槟切┏鰲5膶?duì)象即使程序其它對(duì)象不再引用,但是Stack類中的elements[]數(shù)組依然保存著這些對(duì)象的引用,導(dǎo)致這些對(duì)象不會(huì)被垃圾回收所回收,所以,當(dāng)需要類自己管理內(nèi)存事,要警惕內(nèi)部維護(hù)的這些過(guò)期引用是否被及時(shí)解除了引用,本例中只需在出棧后,顯示的將

elements[size] = null;即可。

緩存是要警惕內(nèi)存泄漏
出現(xiàn)這樣情況通常是一旦將對(duì)象放入緩存,很可能長(zhǎng)時(shí)間不使用很容易遺忘,通常可以用WakeHashMap代表緩存,在緩存中的項(xiàng)過(guò)期后,他們可以被自動(dòng)刪除。或者可以由一個(gè)后臺(tái)線程定期執(zhí)行來(lái)清除緩沖中的過(guò)期項(xiàng)。

監(jiān)聽器或回調(diào)的注冊(cè),最好可以顯示的取消注冊(cè)。
2、不要手動(dòng)調(diào)用finalize(),它是給垃圾回收器調(diào)用的

3、避免使用finalize()方法,除非用來(lái)作為判斷終結(jié)條件以發(fā)現(xiàn)對(duì)象中沒有被適當(dāng)清理的部分;用來(lái)作為安全網(wǎng)在手動(dòng)清理忘記調(diào)用的情況下清理系統(tǒng)資源,延后清理總別永不清理要強(qiáng),并且如果同時(shí)記錄下忘記清理資源的信息的話,也方便后面發(fā)現(xiàn)錯(cuò)誤,并及時(shí)修改忘記清理的代碼;釋放對(duì)象中本地方法獲得的不是很關(guān)鍵的系統(tǒng)資源。

finalize()方法由于其執(zhí)行時(shí)間以及是否確定被執(zhí)行都不能準(zhǔn)確確保,所以最好不用來(lái)釋放關(guān)鍵資源,但是可用于上面所說(shuō)的三種情況。其中第一種情況,示例如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Book {
 boolean checkout = false;
 public Book(boolean checkout) {
  this.checkout = checkout;
 }
 
 public void checkin(){
  checkout = false;
 }
 
 @Override
 protected void finalize() throws Throwable {
  if (checkout) {
   System.out.println("Error: check out");
  }
 }
}
 
public class FinalizeCheckObjectUse {
 
 public static void main(String[] args) {
  new Book(true);
  System.gc();
 }
 
}

執(zhí)行結(jié)果:

Error: check out
例子中的Book對(duì)象,在釋放前必須處于checkIn的狀態(tài),否則不能釋放,finalize中的實(shí)現(xiàn)可以幫助及時(shí)發(fā)現(xiàn)不合法的對(duì)象,或者更直接的,在finalize中直接使用某個(gè)引用變量引用,使其重新進(jìn)入reachable的狀態(tài),然后再次對(duì)其進(jìn)行處理。

另一點(diǎn)需要注意的時(shí),子類如果覆蓋了父類的finalize方法,但是忘了手工調(diào)用super.finalize或者子類的finalize過(guò)程出現(xiàn)異常導(dǎo)致沒有執(zhí)行到super.finalize時(shí),那么父類的終結(jié)方法將永遠(yuǎn)不會(huì)調(diào)到。

如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Parent{
  @Override
  protected void finalize() throws Throwable {
    System.out.println(getClass().getName() + " finalize start");
  }
}
 
class Son extends Parent{
  @Override
  protected void finalize() throws Throwable {
    System.out.println(getClass().getName() + " finalize start");
  }
}
public class SuperFinalizeLost {
 
  public static void main(String[] args) {
    new Son();
    System.gc();
  }
 
}

運(yùn)行結(jié)果:

Son finalize start
或者

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Parent{
  @Override
  protected void finalize() throws Throwable {
    System.out.println(getClass().getName() + " finalize start");
  }
}
 
class Son extends Parent{
  @Override
  protected void finalize() throws Throwable {
    System.out.println(getClass().getName() + " finalize start");
    int i = 5 / 0;
    super.finalize();
  }
}
public class SuperFinalizeLost {
 
  public static void main(String[] args) {
    new Son();
    System.gc();
  }
 
}

執(zhí)行結(jié)果:

Son finalize start
對(duì)于第二種情況,可以使用try...finally...結(jié)構(gòu)解決,但是對(duì)于第一種情況,最好使用一種叫終結(jié)方法守護(hù)者的方式。示例如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Parent2{
  private final Object finalizeGuardian = new Object() {
    protected void finalize() throws Throwable {
      System.out.println("在此執(zhí)行父類終結(jié)方法中的邏輯");
    };
  };
}
 
class Son2 extends Parent2{
  @Override
  protected void finalize() throws Throwable {
    System.out.println(getClass().getName() + " finalize start");
    int i = 5 / 0;
    super.finalize();
  }
}
 
public class FinalizeGuardian {
 
  public static void main(String[] args) {
    new Son2();
    System.gc();
  }
 
}

執(zhí)行結(jié)果:

在此執(zhí)行父類終結(jié)方法中的邏輯
Son2 finalize start
這樣可以保證父類的終結(jié)方法中所需做的操作執(zhí)行到。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 色播视频在线播放 | 日本免费aaa观看 | 福利在线小视频 | 欧美一级黄 | 91久久线看在观草草青青 | 717影院理论午夜伦八戒秦先生 | 亚洲一区二区三区精品在线观看 | 斗破苍穹在线观看免费完整观看 | 羞羞的网站 | 国产一区二区三区四区在线 | 免费h片| 91久久久久久久久久久久久久 | 亚洲爱爱网站 | 亚洲热线99精品视频 | 九九热视频这里只有精品 | 九九热视频在线免费观看 | 精品久久久久久国产三级 | 国产视频在线观看免费 | 久久久毛片视频 | 成人毛片网 | 久久成人视屏 | 成人aaaa免费全部观看 | 一级做a爰性色毛片免费 | 九色中文字幕 | 成年人免费高清视频 | 国产精品一区二区日韩 | 韩国精品一区二区三区四区五区 | 国产精品久久久久影院老司 | 久久久一区二区精品 | xxxx69hd一hd72 | 日韩在线播放一区二区 | 911色_911色sss主站色播 | 美女黄网站免费观看 | 亚洲人成网站免费播放 | 午夜精品小视频 | 成人免费观看av | 欧美一级黑人 | 国产亚洲精品久久久闺蜜 | 免费看综艺策驰影院 | 在线看小早川怜子av | 精品一区二区三区电影 |