JVM垃圾回收机制总结(6) :透视Java的GC特性
1、 使用 System.gc() 可以不管JVM使用的是哪一种垃圾回收的算法,都可以请求 Java的垃圾回收。 在命令行中有一个参数-verbosegc可以查看Java使用的堆内存的情况,它的格式:java -verbosegc classfile
- class TestGC {
- public static void main(String[] args) {
- new TestGC();
- System.gc();
- System.runFinalization();
- }
- }
- class TestGC {
- public static void main(String[] args) {
- new TestGC();
- System.gc();
- System.runFinalization();
- }
- }
在这个例子 中,一个新的对象被创建,由于它没有使用,所以该对象迅速地变为可达,程序编译后,执行命令: java -verbosegc TestGC 后结果为:
[Full GC 168K->97K(1984K), 0.0253873 secs]
机器的环 境为,Windows 2000 + JDK1.3.1,箭头前后的数据168K和97K分别表示垃圾收集GC前后所有存活对象使用的内存容量,说明有168K-97K=71K的对象容量被回 收,括号内的数据1984K为堆内存的总容量,收集所需要的时间是0.0253873秒(这个时间在每次执行的时候会有所不同)。
2、 finalize方法 透视垃圾收集器的运行
在JVM垃圾收集器收集一个对象之前 ,一般要求程序调用适当的方法释放资源,但在没有明确释放资源的情况下,Java提供了缺省机制来终止化该对象心释放资源,这个方法就是 finalize()。它的原型为:
Java代码
1. protected void finalize() throws Throwable
在finalize()方法返回之后,对象消失,垃圾收集开始执行。原型中的throws Throwable表示它可以抛出任何类型的异常。
之所以要使用finalize(),是由于有时需要采取与Java的普通方法不同的一种方法,通过分配内存来做一些具有C风格的事情。这主要可以通过" 固有方法"来进行,它是从Java里调用非Java方法的一种方式。C和C++是目前唯一获得固有方法支持的语言。但由于它们能调用通过其他语言编写的子 程序,所以能够有效地调用任何东西。在非Java代码内部,也许能调用C的malloc()系列函数,用它分配存储空间。而且除非调用了free(),否 则存储空间不会得到释放,从而造成内存"漏洞"的出现。当然,free()是一个C和C++函数,所以我们需要在finalize()内部的一个固有方法 中调用它。也就是说我们不能过多地使用finalize(),它并不是进行普通清除工作的理想场所。
在普通的清除工作中,为清除一个 对象,那个对象的用户必须在希望进行清除的地点调用一个清除方法。这与C++"破坏器"的概念稍有抵触。在C++中,所有对象都会破坏(清除)。或者换句 话说,所有对象都"应该"破坏。若将C++对象创建成一个本地对象,比如在堆栈中创建(在Java中是不可能的),那么清除或破坏工作就会在"结束花括 号"所代表的、创建这个对象的作用域的末尾进行。若对象是用new创建的(类似于Java),那么当程序员调用C++的delete命令时(Java没有 这个命令),就会调用相应的破坏器。若程序员忘记了,那么永远不会调用破坏器,我们最终得到的将是一个内存"漏洞",另外还包括对象的其他部分永远不会得 到清除。
相反,Java不允许我们创建本地(局部)对象--无论如何都要使用new。但在Java中,没有"delete"命令来释 放对象,因为垃圾收集器会帮助我们自动释放存储空间。所以如果站在比较简化的立场,我们可以说正是由于存在垃圾收集机制,所以Java没有破坏器。然而, 随着以后学习的深入,就会知道垃圾收集器的存在并不能完全消除对破坏器的需要,或者说不能消除对破坏器代表的那种机制的需要(而且绝对不能直接调用 finalize(),所以应尽量避免用它)。若希望执行除释放存储空间之外的其他某种形式的清除工作,仍然必须调用Java中的一个方法。它等价于 C++的破坏器,只是没后者方便。
下面这个例子向大家展示了垃圾收集所经历的过程,并对前面的陈述进行了总结。
- package hr.test;
- import java.util.Calendar;
- class Chair {
- static int created = 0; //对象创建计数
- static int finalized = 0; //对象回收计数
- //构造器
- Chair(){
- created++;
- System.err.println("created "+created+"【"+Calendar.getInstance().get(Calendar.MINUTE)+"m "+Calendar.getInstance().get(Calendar.SECOND)+"s】");
- }
- //垃圾回收析构函数
- protected void finalize() {
- finalized++;
- System.out.println("finalize "+finalized+"【"+Calendar.getInstance().get(Calendar.MINUTE)+"m "+Calendar.getInstance().get(Calendar.SECOND)+"s】");
- }
- }
- public class Garbage {
- public static void main(String[] args) {
- while(Chair.created!=10000) {
- new Chair();//创建对象
- }
- while(true){
- if(Chair.created==10000){
- break;
- }
- }
- }
- }
上面这个程序创建了10000个Chair对象。但是在运行结果中发现,在累计循环创建到x个对象的时候,我们发现主线程被挂起,JVM开始运行垃圾 回收程序。证据就是屏幕上开始打印出"final ..."。而且主线程被挂起的时间是不定的,有的时候我们甚至能在输出中看到半条"create.. "就开始打印"final ..."了。
经过上述的说明,可以发现垃圾回收有以下的几个特点:
(1) 垃圾收集发生的不可预 知性: 由于实现了不同的垃圾收集算法和采用了不同的收集机制,所以它有可能是定时发生,有可能是当出现系统空闲CPU资源时发生,也有可能是和原始的垃圾 收集一样,等到内存消耗出现极限时发生,这与垃圾收集器的选择和具体的设置都有关系。
(2)垃圾收集的精确性: 主要包括2 个方面:(a)垃圾收集器能够精确标记活着的对象; (b)垃圾收集器能够精确地定位对象之间的引用关系。 前者是完全地回收所有废弃对象的前提,否则就可能 造成内存泄漏。而后者则是实现归并和复制等算法的必要条件。所有不可达对象都能够可靠地得到回收,所有对象都能够重新分配,允许对象的复制和对象内存的缩 并,这样就有效地防止内存的支离破碎。
(3)现在有许多种不同的垃圾收集器,每种有其算法且其表现各异,既有当垃圾收集开始时就 停止应用程序的运行,又有当垃圾收集开始时也允许应用程序的线程运行,还有在同一时间垃圾收集多线程运行。
(4)垃圾收集的实现 和具体的JVM 以及JVM的内存模型有非常紧密的关系。 不同的JVM 可能采用不同的垃圾收集,而JVM 的内存模型决定着该JVM可以采用哪些类型垃圾收集。现在,HotSpot 系列JVM中的内存系统都采用先进的面向对象的框架设计,这使得该系列JVM都可以采用最先进的垃圾收集。
(5)随着技术的发 展,现代垃圾收集技术提供许多可选的垃圾收集器,而且在配置每种收集器的时候又可以设置不同的参数,这就使得根据不同的应用环境获得最优的应用性能成为可能。
针对以上特点,我们在使用的时候要注意:
(1)不要试图去假定垃圾收集发生的时间,这一切都是未知 的。 比如,方法中的一个临时对象在方法调用完毕后就变成了无用对象,这个时候它的内存就可以被释放。
(2)Java中提供了一些 和垃圾收集打交道的类,而且提供了一种强行执行垃圾收集的方法--调用System.gc(),但这同样是个不确定的方法。 Java 中并不保证每次调用该方法就一定能够启动垃圾收集,它只不过会向JVM发出这样一个申请,到底是否真正执行垃圾收集,一切都是个未知数。
(3)挑选适合自己的垃圾收集器。 一般来说,如果系统没有特殊和苛刻的性能要求,可以采用JVM的缺省选项。 否则可以考虑使用有针对性的垃圾收集器,比 如增量收集器就比较适合实时性要求较高的系统之中。系统具有较高的配置,有比较多的闲置资源,可以考虑使用并行标记/清除收集器。
(4)关键的也是难把握的问题是内存泄漏。 良好的编程习惯和严谨的编程态度永远是最重要的,不要让自己的一个小错误导致内存出现大漏洞。
(5)尽早释放无用对象的引用。 大多数程序员在使用临时变量的时候,都是让引用变量在退出活动域(scope)后,自动设置为null,暗示垃圾收集器 来收集该对象,还必须注意该引用的对象是否被监听,如果有,则要去掉监听器,然后再赋空值。
结束语
一般 来说,Java开发人员可以不重视JVM中堆内存的分配和垃圾处理收集,但是,充分理解Java的这一特性可以让我们更有效地利用资源。同时要注意 finalize()方法是Java的缺省机制,有时为确保对象资源的明确释放,可以编写自己的finalize方法。
JVM垃圾回收机制总结(6) :透视Java的GC特性的更多相关文章
- Java虚拟机学习笔记——JVM垃圾回收机制
Java虚拟机学习笔记——JVM垃圾回收机制 Java垃圾回收基于虚拟机的自动内存管理机制,我们不需要为每一个对象进行释放内存,不容易发生内存泄漏和内存溢出问题. 但是自动内存管理机制不是万能药,我们 ...
- JVM内存管理和JVM垃圾回收机制
JVM内存管理和JVM垃圾回收机制(1) 这里向大家描述一下JVM学习笔记之JVM内存管理和JVM垃圾回收的概念,JVM内存结构由堆.栈.本地方法栈.方法区等部分组成,另外JVM分别对新生代和旧生代采 ...
- JVM基础系列第8讲:JVM 垃圾回收机制
在第 6 讲中我们说到 Java 虚拟机的内存结构,提到了这部分的规范其实是由<Java 虚拟机规范>指定的,每个 Java 虚拟机可能都有不同的实现.其实涉及到 Java 虚拟机的内存, ...
- JVM内存管理、JVM垃圾回收机制、新生代、老年代以及永久代
内存模型 JVM运行时数据区由程序计数器.堆.虚拟机栈.本地方法栈.方法区部分组成,结构图如下所示. JVM内存结构由程序计数器.堆.栈.本地方法栈.方法区等部分组成,结构图如下所示: 1)程序计数器 ...
- JVM 垃圾回收机制和常见算法和 JVM 的内存结构和内存分配(面试题)
一.JVM 垃圾回收机制和常见算法 Sun 公司只定义了垃圾回收机制规则而不局限于其实现算法,因此不同厂商生产的虚拟机采用的算法也不尽相同.GC(Garbage Collector)在回收对象前首先必 ...
- JVM垃圾回收机制和常用算法
由于疫情的原因,所以目前一直在家远程办公,所以很多时间在刷面试题,发现2019大厂的面试虽然种类很多,但是总结了一下发现主要是这几点:算法和数据结构. JVM.集合.多线程.数据库这几点在面试的时候比 ...
- 真的可惜,四面阿里,结果我被JVM垃圾回收机制与 OOM异常卡住了
前言 为什么需要垃圾回收 首先我们来聊聊为什么会需要垃圾回收,假设我们不进行垃圾回收会造成什么后果,我们举一个简单的例子 我们住在一个房子里面,我们每天都在里面生活,然后垃圾都丢在房子里面,又不打扫, ...
- JVM垃圾回收机制总结:调优方法
转载: JVM垃圾回收机制总结:调优方法 JVM 优化经验总结 JVM 垃圾回收器工作原理及使用实例介绍
- JVM垃圾回收机制概述
JVM垃圾回收机制概述 1.定义 是指JVM用于释放那些不再使用的对象所占用的内存. 2.方式 2.1引用计数(早期) 当引用程序创建引用以及引用超出范围时,JVM必须适当增减引用数.当某个对象的引用 ...
- java JVM垃圾回收机制
Java语言出来之前,大家都在拼命的写C或者C++的程序,而此时存在一个很大的矛盾,C++等语言创建对象要不断的去开辟空间,不用的时候有需要不断的去释放控件,既要写构造函数,又要写析构函数,很多时候都 ...
随机推荐
- linux中的文件类型
1.使用ls -l命令可以查看文件的类型和权限 [tansheng@localhost etc]$ ls -l ----------. root root 10月 : gshadow -------- ...
- C++类中的this指针的作用
1.我们知道C++的类成员函数中,默认都隐含了一个this指针,标识调用该成员函数的对象 2.为什么需要有一个this指针呢?C++设计这个机制的初衷是什么呢? 我们知道,普通的C++类,其成员函数是 ...
- Android -- Home按键
游戏中常常需要监听android HOME键,当HOME键下压时,往往需要做一些状态保存,音效停止等操作,那么如何做,才能监听到HOME键呢?我们知道HOME是系统键,app中无法通过onKey这些函 ...
- hdu 1075 What Are You Talking About
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1075 题意:比较简单,易懂,这里不做说明. 解法:第一种方法:用map映射,耗时1000+ms:第二种 ...
- 引擎设计跟踪(九.14.2c) 最近一些小的更新
1. bump map与normal map 昨天拿了crytek sponza(http://www.crytek.com/cryengine/cryengine3/downloads)场景测试, ...
- IDA 在string窗口中显示中文字符串
打开ida61\cfg中的ida.cfg文件找到 // (cp866 version)AsciiStringChars = "\r\n\a\v\b\t\x1B" " !\ ...
- spring mvc Controller与jquery Form表单提交代码demo
1.JSP表单 <% String basePath = request.getScheme() + "://" + request.getServerName() +&qu ...
- JavaScript文件应该放在网页的什么位置
JavaScript文件应该放在网页的什么位置 http://www.lihuai.net/qianduan/js/352.html 在<良好的JavaScript编程习惯>系列教程的第三 ...
- Activity学习(四)——简单切换
理论学习Activity之后,我们就来具体的实战,Activity之间相互切换依靠的是“ 意图 ”(Intent),这个 Intent 包含了要跳转到的Activity的一些信息,因为Activity ...
- SQL语句AND 和 OR执行的优先级
例句: ) FROM RT_CUSTALLOCRESULT WHERE REGDATE BETWEEN '2014-03-01' AND '2014-03-31' ) FROM RT_CUSTALLO ...