为什么JAVA的垃圾回收机制无法避免内存泄漏
生活随笔
收集整理的這篇文章主要介紹了
为什么JAVA的垃圾回收机制无法避免内存泄漏
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
一、本文參考: 1.《深入理解java虛擬機(jī) JVM高級(jí)特性與最佳實(shí)踐》 2.http://coderevisited.com/memory-leaks-in-java/ 二、對(duì)象已死的判定方法 要進(jìn)行JVM中對(duì)象回收首先要判斷對(duì)象是否已經(jīng)死亡,判斷的方法有如下幾個(gè): 1.引用計(jì)數(shù)法 給對(duì)象中添加一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器值就加1;當(dāng)引用失效時(shí),計(jì)數(shù)器值就減1;任何時(shí)刻 計(jì)數(shù)器為0的對(duì)象就是不可能再被使用的。 但是主流的java虛擬機(jī)里面沒有選用引用計(jì)數(shù)器算法來管理內(nèi)存,其中最主要的原因是它很難解決對(duì)象之間相互循環(huán)引用的問題。 2.可達(dá)性分析算法 這個(gè)算法的基本思想就是通過一系列的稱為“GC Roots"的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索所走過的路徑稱為引用鏈,當(dāng)一個(gè)對(duì)象到GC Roots沒有任何引用鏈相連接時(shí),則證明此對(duì)象是不可用的。如下圖所示,對(duì)象object5、object6、object7雖然互相有關(guān)聯(lián),但是它們到GC Roots是不可達(dá)的,所以它們將會(huì)被判定為是可回收對(duì)象。 三、導(dǎo)致內(nèi)存泄漏的情況及代碼 java 堆內(nèi)存泄漏。是由于java對(duì)象不停創(chuàng)建但是沒有釋放對(duì)象引用導(dǎo)致的。 以下是關(guān)于java代碼,此代碼是引自http://coderevisited.com/memory-leaks-in-java/ 類com.code.revisited.memoryleaks.Stack提供了實(shí)現(xiàn)棧的一些方法,包括遍歷,入棧,出棧等操作。假設(shè)原來目的是為了現(xiàn)實(shí)使用(當(dāng)然這里是為了解釋內(nèi)存泄漏)。 package com.code.revisited.memoryleaks;import java.util.Iterator;
import java.util.NoSuchElementException;/*** @author sureshsajja* */
public class Stack<E> implements Iterable<E> {private int N;private E[] array;@SuppressWarnings("unchecked")public Stack(int capacity) {array = (E[]) new Object[capacity];}@Overridepublic Iterator<E> iterator() {return new StackIterator();}private class StackIterator implements Iterator<E> {private int i = N - 1;@Overridepublic boolean hasNext() {return i >= 0;}@Overridepublic E next() {if (!hasNext()) {throw new NoSuchElementException();}return array[i--];}@Overridepublic void remove() {throw new UnsupportedOperationException();}}public void push(E item) {if (isFull()) {throw new RuntimeException("Stack overflow");}array[N++] = item;}public E pop() {if (isEmpty())throw new RuntimeException("Stack underflow");E item = array[--N];return item;}public boolean isEmpty() {return N == 0;}public int size() {return N;}public boolean isFull() {return N == array.length;}public E peek() {if (isEmpty())throw new RuntimeException("Stack underflow");return array[N - 1];}}
類com.code.revisited.memoryleaks.StackTest用于執(zhí)行棧操作。要進(jìn)行入棧及出棧10000次操作,理想是入棧時(shí)分配堆內(nèi)存,出棧后對(duì)象被回收。
package com.code.revisited.memoryleaks;/*** @author sureshsajja**/ public class StackTest {/*** @param args*/public static void main(String[] args) {Stack<Integer> s = new Stack<Integer>(10000);for (int i = 0; i < 10000; i++) {s.push(i);}while (!s.isEmpty()) {s.pop();}while (true ) {// do something }}} 執(zhí)行開始。我們使用VisualVM進(jìn)行觀察。為了更明顯一些,將棧操作部分代碼注釋也執(zhí)行一下。 package com.code.revisited.memoryleaks;/*** @author sureshsajja**/ public class StackTest {/*** @param args*/public static void main(String[] args) { // Stack<Integer> s = new Stack<Integer>(10000); // for ( int i = 0; i < 10000; i++) { // s.push(i); // } // // while (!s.isEmpty()) { // s.pop(); // }while (true ) {// do something }}}把棧操作的設(shè)為1號(hào),沒有棧操作的設(shè)置為2號(hào),分別生成Heap Dump文件,我們看一下類實(shí)例的截圖:
首先是1號(hào)截圖 首先是2號(hào)截圖 顯然預(yù)期的棧操作出棧后并沒有釋放掉Integer對(duì)象的引用(實(shí)際上看代碼也知道),所以不會(huì)被GC回收。真正的實(shí)際情況這種引用將會(huì)很隱蔽,但是根本總是由于對(duì)象仍然被引用。 四、結(jié)語(yǔ) 本篇僅對(duì)java堆內(nèi)存泄漏進(jìn)行了簡(jiǎn)單說明,下一篇將討論其他相關(guān)的內(nèi)存泄漏。有不對(duì)的地方歡迎拍磚>_<轉(zhuǎn)載于:https://www.cnblogs.com/bobsha/p/5228335.html
總結(jié)
以上是生活随笔為你收集整理的为什么JAVA的垃圾回收机制无法避免内存泄漏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux安装docker部署java项
- 下一篇: 【代码笔记】iOS-点击城市中的tabl