`

6、内存管理机制---垃圾收集器(上)

 
阅读更多

       1960年 MIT(麻省理工学院 Massachusetts Institute of Technology )Lisp语言 第一次使用动态内存分配和垃圾收集技术;

        那些内存需要被释放

        在什么时候释放

        怎样实现释放

 

       程序计数器、jvm栈、本地方法栈随 线程创建和释放(不由GC回收),栈中的栈帧随方法的进入和退出顺序执行入栈和出,每个栈帧的大小在编译时确定(无动态扩张情况);

       垃圾收集器对堆回收前,判断对象在后面的程序还要被调用,或者不再被调用,  判断方法:

1、引用计算法:在调用时,计数器值+1;调用结束时,计数器值-1;当计数器值为0时不能再被调用,适用大部分gc算法;但不能解决对象循环互调;

2、可达性分析算法  通过"GC Roots"对象作为起始点,从起始节点开始向下搜索,走过的路径称为引用链(reference chain),当一个对象与GC Roots没有链接时,则该对象是不可用的。

可以作为GC Roots对象包括:

  • jvm栈(栈中本地变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象 (单例模式 final A a;)
  • JNI(c++)中引用的对象

1.2之后对引用进行看扩充,将引用分为:

强引用(String Reference),类似 A a = new A(),只要a还会使用,收集器不会收集a空间

软引用(Soft Reference), 弱引用被回收后,还是不能消除内存溢出,溢出前回收 软引用空间

弱引用(Weak Reference),下次gc收集垃圾时,被回收

虚引用(Phantom Reference);关联对象,在对象被回收之前返回一个系统信息,不能通过虚引用取得实例,该空间已被回收;

 

 

对象的自我救赎finalize()

一个对象被回收前至少要经历两次标记,可达性分析后发现与GC Roots没有连接时,将进行第一次标记, 并筛选该对象是否需要执行finalize()方法;  如果该对象被判定有必要执行finalize方法则将放入F-Queue列队,由低级Finalizer线程去触发它,finalize()提供给对象最后一次不回收的机会,只要和引用链上任何一个对象建立关联即可:

public class Test { 
	public static  Test t=null;
	public void isAlive(){
		System.out.println("still here");
	}
	protected void finalize(){
		System.out.println("执行finalize方法");
		t = this;  //自我引用
	}
	public static void main(String...s) throws Exception{
		t = new Test();
		t=null;
		System.out.println("is here ?");
		System.gc();
		//执行gc()时触发finalize()方法,finalize方法优先级很低,不设置等待,就会出现没有执行就执行下一条语句了;
		Thread.sleep(500);
		t.isAlive();
		System.out.println(t.hashCode());
		//执行了finalize()方法,t复活了,但只能复活一次,若再执行:
		t=null;
		System.out.println("is here ?");
		System.gc();
		Thread.sleep(500);
	    //判定对象t是否还在heap中存在
		System.out.println(t==null);
	}
}

输出:

is here ?

执行finalize方法

still here            //heap中还存在

5629279

is here ?

true            //表示已被回收

原书作者不建议使用此方法复活对象;

 

回收方法区,jvm规范中讲过可以不要求jvm对方法区的垃圾回收,因为能释放的空间很少。永久代的垃圾收集主要有两部分:废弃常量和无用的类。

回收常量与回收heap类似,而回收无用的类比较复杂,判断是否为无用的类:

  • java  heap中不存在该类的任何实例
  • 该类的类类加载已经被回收
  • 该类的Class对象没有被任何地方引用

 

$垃圾收集算法:

标记-清除(Mark- sweep)

标记-整理(Mark- compact)

复制(Copying)

分代收集算法(老年代、新生代),新生代中98%的会被回收,将新生代分为Eden(大块)、两个survival;每次使用Eden和其中一个survival,当回收时,将Eden和survival中存活的对象一次性的复制到另外一块survival空间上,然后格式化Eden和刚才用过的survival空间,HotSpot默认Eden与survival大小比例8:1,新生代中的90%用来装载新生对象,10%用来转载存活的对象。

 

HotSpot的算法实现(详见下章): 

          枚举根节点:可达性分析必须在一个一致性的快照中进行-即整个分析期间,系统就像冻结了一样。否则如果一边分析,系统一边动态表化,得到的结果就没有准确性。这就导致了系统GC时必须停顿所有的Java执行线程。在HotSpot实现中,使用一组称为 OopMap 的数据结构来存放对象引用。OopMap会在类加载完成的时候,记录对象内什么偏移量上是什么类型的数据,在JIT编译过程中,也会在特定的位置记录下栈和寄存器哪些位置是引用。

 

          安全点:OopMap内容变化的指令非常多,HotSpot并不会为每条指令都产生OopMap,只是在特定的位置记录了这些信息,这些位置成为“安全点”(SafePoint)。程序执行时只有在达到安全点的时候才停顿开始GC。一般具有较长运行时间的指令才能被选为安全点,如方法调用、循环跳转、异常跳转等。接下来要考虑的便是,如何在GC时保证所有的线程都“跑”到安全点上停顿下来。这里有两种方案:

抢先式中断 (Preemptive Suspension) 和主动式中断 (Voluntary Suspension)。

抢先式中断会把所有线程中断,如果某个线程不在安全点上,就恢复让它跑到安全点上。几乎没有虚拟机采用这种方式。

主动式中断思想是设立一个GC标志,各个线程会轮询这个标志并在需要时自己中断挂起。这样,标志和安全点是重合的。

 

           安全区域:Safepoint机制可以保证某一程序在运行的时候,在不长的时间里就可以进入GC的Safepoint。但是如果程序没有分配CPU时间,例如处于Sleep状态或者Blocked状态,这时候线程无法响应JVM的中断请求。对于这种情况,只能用 安全区域 (Safe Region)来解决。安全区域是指在一段代码片段之中,引用关系不会发生变化。在这个区域中任意地方开始都是安全的。在线程执行到Safe Region中的代码时,就标记自己已经进入了Safe Region,这样JVM在发起GC时就跳过这些线程。在线程要离开Safe Region时,它要检查系统是否已经完成了枚举(或GC过程),如果完成了线程就继续执行,否则就等待。

 

 

分享到:
评论

相关推荐

    JVM自动内存管理机制

    Java自动内存管理机制包含两部分:内存分配和内存回收,要想理解内存分配和回收的机制,则需要了解下Java内存区域(Java运行时数据区),这篇随笔将按照下面的线索进行逐步解析:1.Java运行时数据区2.对象“已死”的...

    内存管理内存管理内存管理

    对实际编程来说,理解您的内存管理器的能力与局限性至关重要。在大部分系统语言中,比如 C 和 C++,您必须进行内存管理。本文将介绍手工的、半手工的以及自动的内存管理实践的基本概念。 追溯到在 Apple II 上...

    《垃圾收集》(Garbage Collection)扫描版[PDF]——part2

    10.2 对C++垃圾收集器的需求 10.3 在编译器中还是在库中 10.4 保守式垃圾收集 10.5 准复制式收集器 10.6 智能指针 10.6.1 在没有智能指针类层次的情况下进行转换 10.6.2 多重继承 10.6.3 不正确的转换 10.6.4 某些...

    操作系统(内存管理)

    文中将为您提供如何管理内存的细节,然后将进一步展示如何手工管理内存,如何使用引用计数或者内存池来半手工地管理内存,以及如何使用垃圾收集自动管理内存。 为什么必须管理内存 内存管理是计算机编程最为基本的...

    Java垃圾回收知识,垃圾回收资料

    知识点覆盖范围:垃圾回收算法、垃圾收集器、GC原理、垃圾回收的优缺点等。 难度级别:从基础到高级,面试官可能会深入探讨垃圾回收的细节和实现原理。 实践经验:理论知识之外,面试官可能会问到实际场景下的优化...

    resin-jvm 调优

    理解了应用程序的工作负荷和jvm支持的垃圾收集算法,便可以进行优化配置垃圾收集器。 垃圾收集的目的在于清除不再使用的对象。gc通过确定对象是否被活动对象引用来确定是否收集该对象。gc首先要判断该对象是否是...

    跟我学习javascript的垃圾回收机制与内存管理

    原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。 JavaScript垃圾回收的机制很简单:找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是实时的,因为其开销比较大,所以...

    基于TCP的服务器客户端程序设计.doc

    重庆交通大学信息科学与工程学院 课程...Java舍弃了C ++语言中容易引起错误的指针(以引用取代)、运算符重载(operator overloading)、多重继承(以接口取代)等特性,增加了垃圾回收器功能用于回收不再...

    javascript垃圾收集机制与内存泄漏详细解析

    为此,垃圾收集器会按照固定的时间间隔(或代码执行中预设的收集时间),周期性的执行这一操作。 下面我们来分析一下函数中局部变量正常的生命周期。局部变量只在函数执行的过程中存在。而在这个过程中,

    (Garbage Collection)扫描版——part1

    10.2 对C++垃圾收集器的需求 10.3 在编译器中还是在库中 10.4 保守式垃圾收集 10.5 准复制式收集器 10.6 智能指针 10.6.1 在没有智能指针类层次的情况下进行转换 10.6.2 多重继承 10.6.3 不正确的转换 10.6.4 某些...

    浅谈JavaScript的自动垃圾收集机制

    为此,垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间)周期性地执行这一操作。 垃圾收集的方式: 1.标记清除(mark-and-sweep)  最常用的垃圾收集方式。当变量进入环境时,就将变量标记为“进入...

    javascript垃圾收集机制的原理分析

     垃圾收集机制的原理很简单:找出那些不再继续使用的变量,然后释放其占用的内存,垃圾收集器会按照固定的时间间隔,或代码执行中预定的收集时间,周期性地执行这一操作  局部变量只在函数执行的过程中存在。而在...

    谈谈JavaScript中的垃圾回收机制

    为此,垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间), 周期性地执行这一操作。  具体到浏览器中的实现,则通常有两个策略,分别为标记清除和引用计数。 一、标记清除  JavaScript 中最常用的垃圾...

    java虚拟机知识点整理

    垃圾收集器GC管理 虚拟机GC垃圾回收收集算法(内存回收方法论) 虚拟机GC垃圾回收收集器(内存回收具体实现) 对象内存分配 虚拟机性能监控与故障处理工具 内存溢出问题及调优 类文件结构 虚拟机类加载机制 编译期编译...

    全面了解JavaScirpt 的垃圾(garbage collection)回收机制

    原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。 JavaScript垃圾回收的机制很简单:找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是实时的,因为其开销比较大,所以...

    cmd操作命令和linux命令大全收集

    4. explorer-------打开资源管理器 5. logoff---------注销命令 6. shutdown-------60秒倒计时关机命令 7. lusrmgr.msc----本机用户和组 8. services.msc---本地服务设置 9. oobe/msoobe /a----检查XP是否激活 ...

    最新java面试专题01-JVM

    最新jvm面试题合集,涵盖JVM运行时数据区、垃圾回收算法、...垃圾收集器可以根据不同的算法和策略进行配置和优化,以提高内存使用效率和性能。 类加载机制:JVM通过类加载器加载类文件,将其转换为可执行的二进制格式。

    Java面试技术面知识扩展包第三弹.rar

    3. 自动内存管理:Java使用垃圾收集器(Garbage Collector)自动管理内存。开发者不需要手动进行内存分配和释放,通过“对象生命周期”的概念,垃圾收集器会自动回收不再使用的内存。 4. 异常处理:Java提供了异常...

    Java面试技术面知识扩展包第二弹.rar

    3. 自动内存管理:Java使用垃圾收集器(Garbage Collector)自动管理内存。开发者不需要手动进行内存分配和释放,通过“对象生命周期”的概念,垃圾收集器会自动回收不再使用的内存。 4. 异常处理:Java提供了异常...

Global site tag (gtag.js) - Google Analytics