一、本文参考:
   1.《深入理解java虚拟机 JVM高级特性与最佳实践》
 
二、对象已死的判定方法
      要进行JVM中对象回收首先要判断对象是否已经死亡,判断的方法有如下几个:
     1.引用计数法
         给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻 计数器为0的对象就是不可能再被使用的。
 但是主流的java虚拟机里面没有选用引用计数器算法来管理内存,其中最主要的原因是它很难解决对象之间相互循环引用的问题。
 
     2.可达性分析算法
     这个算法的基本思想就是通过一系列的称为“GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连接时,则证明此对象是不可用的。如下图所示,对象object5、object6、object7虽然互相有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收对象。
 
 
三、导致内存泄漏的情况及代码
 
java 堆内存泄漏。是由于java对象不停创建但是没有释放对象引用导致的。
以下是关于java代码,此代码是引自http://coderevisited.com/memory-leaks-in-java/
 
类com.code.revisited.memoryleaks.Stack提供了实现栈的一些方法,包括遍历,入栈,出栈等操作。假设原来目的是为了现实使用(当然这里是为了解释内存泄漏)。

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];
} @Override
public Iterator<E> iterator() {
return new StackIterator();
} private class StackIterator implements Iterator<E> { private int i = N - 1; @Override
public boolean hasNext() {
return i >= 0;
} @Override
public E next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return array[i--];
} @Override
public 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用于执行栈操作。要进行入栈及出栈10000次操作,理想是入栈时分配堆内存,出栈后对象被回收。

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
} } }
执行开始。我们使用VisualVM进行观察。为了更明显一些,将栈操作部分代码注释也执行一下。
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
} } }

把栈操作的设为1号,没有栈操作的设置为2号,分别生成Heap Dump文件,我们看一下类实例的截图:

首先是1号截图
首先是2号截图
显然预期的栈操作出栈后并没有释放掉Integer对象的引用(实际上看代码也知道),所以不会被GC回收。真正的实际情况这种引用将会很隐蔽,但是根本总是由于对象仍然被引用。
  
四、结语
  本篇仅对java堆内存泄漏进行了简单说明,下一篇将讨论其他相关的内存泄漏。有不对的地方欢迎拍砖>_<

为什么JAVA的垃圾回收机制无法避免内存泄漏的更多相关文章

  1. js 垃圾回收机制和引起内存泄漏的操作

    垃圾回收机制 JS中最常见的垃圾回收方式是标记清除. 工作原理:是当变量进入环境时,将这个变量标记为“进入环境”.当变量离开环境时,则将其标记为“离开环境”.标记“离开环境”的就回收内存. 工作流程: ...

  2. 记录Java的垃圾回收机制和几种引用

    一.Java的垃圾回收机制 Java的垃圾回收机制(java garbage collection)是Java虚拟机提供的能力,用于在空闲时间以不定时的方式动态回收无任何引用的对象占据的堆内存空间. ...

  3. 了解java中垃圾回收机制

    Java的垃圾回收机制是Java环境自带有的,它不像c语言的malloc申请空间后需要Free()函数来释放,而Java中的代码块中所申请的空间可在程序执行完成后自动释放,但是是有局限性的,代码块所占 ...

  4. 面试官,不要再问我“Java GC垃圾回收机制”了

    Java GC垃圾回收几乎是面试必问的JVM问题之一,本篇文章带领大家了解Java GC的底层原理,图文并茂,突破学习及面试瓶颈. 楔子-JVM内存结构补充 在上篇<JVM之内存结构详解> ...

  5. 【Java学习笔记】Java的垃圾回收机制

    搬以前写的博客[2014-12-30 15:07] 以前很少关注内存的问题,基本没有关注,这方面的小白,原因在于自己都是写的自我娱乐的小程序,不关注性能,不是提供服务.而企业级别的应用在程序稳健性方面 ...

  6. JVM系列(三):java的垃圾回收机制

    java垃圾回收机制介绍    上一篇讲述了JVM的内存模型,了解了到了绝大部分的对象是分配在堆上面的,我们在编码的时候并没有显示的指明哪些对象需要回收,但是程序在运行的过程中是会一直创建对象的,之所 ...

  7. JAVA的垃圾回收机制

    1. 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象:而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾.JVM的 ...

  8. 全面分析Java的垃圾回收机制

    Java的堆是一个运行时数据区,类的实例(对象)从中分配空间.Java虚拟机(JVM)的堆中储存着正在运行的应用程序所建立的所有对象,这些对象通过new.newarray.anewarray和mult ...

  9. java JVM垃圾回收机制

    Java语言出来之前,大家都在拼命的写C或者C++的程序,而此时存在一个很大的矛盾,C++等语言创建对象要不断的去开辟空间,不用的时候有需要不断的去释放控件,既要写构造函数,又要写析构函数,很多时候都 ...

随机推荐

  1. 5-Zend Studio配置

    0-将文件编码设置成utf-8 Window>Preferences>General>Content Types>Text Default encoding:utf-8 1-Z ...

  2. SQL语句增加字段、修改字段、修改类型、修改默认值

    一.修改字段默认值 alter table 表名 drop constraint 约束名字   ------说明:删除表的字段的原有约束 alter table 表名 add constraint 约 ...

  3. iOS 9的升级后的问题处理

    iOS 9变动影响SDK部分: 增加了bitCode编码格式,当SDK不支持bitCode时,用户集成时无法开启bitCode选项. 现象:用户集成SDK后无法编译通过,错误日志里包含了bitCode ...

  4. MiniUI动态添加table表格

    本文将介绍一下,如何用Jquery MiniUi动态添加一行table表格 1.效果展示 ↓ 2.具体代码 <script type="text/javascript"> ...

  5. web学习之Django--安装

    前提有python,easy_install 关于easy_install 的安装,比较简单的装法 : wget -q http://peak.telecommunity.com/dist/ez_se ...

  6. <Interview Problem>二叉树根到叶节点求和值匹配

    题目大意:一颗二叉树,每个节点都有一个Value, 判断根节点到叶节点的路径求和值是否等于某个数Sum. 比如说如下这样一颗二叉树,76是45,21,10这条路径的求和值,77就没有满足条件的路径. ...

  7. linux修改时间

    1.修改linux系统时间 [root@localhost ~]# date -s "2016-10-15 13:15:12" 2.将系统时间和网络服务器时间同步 [root@lo ...

  8. 简述id,instancetype和__kindof的区别

    id: 好处:可以调用任何对象方法 坏处:不能进行编译检查 + (id)person; instancetype 好处:自动识别当前类的对象 坏处:不会提示返回的类型 + (instancetype) ...

  9. python中文乱码问题

    在学习python的时候,当我要print中文的时候,会出现以下提示: py = '你好,世界!'print py File "n2.py", line 1 SyntaxError ...

  10. Netsuite > Foreign Currency Revaluation 外币评估

    MENU: Transactions > Financial > Revalue Open Currency Balances 使用频率: - 每个月月底,结账前, 手工操作. - 或者在 ...